feat(desktop): add auto-sync and sync interval settings

Persist and load auto_sync and sync_interval in settings. Disable sync interval input when auto-sync is off. Add styling for disabled inputs in settings. Preserve project filter when loading filter projects and add selectProject helper for dashboard.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Dries Peeters
2026-02-04 22:10:34 +01:00
parent a53f5a6163
commit ef19bfae7e
2 changed files with 51 additions and 1 deletions
+6
View File
@@ -505,6 +505,12 @@ button, input, select, textarea {
border-color: var(--primary);
}
.settings-section .form-group input:disabled {
background: var(--bg-secondary);
color: var(--text-secondary);
cursor: not-allowed;
}
.settings-section .form-group small {
display: block;
margin-top: 4px;
+45 -1
View File
@@ -135,8 +135,12 @@ function setupEventListeners() {
// Settings
const saveSettingsBtn = document.getElementById('save-settings-btn');
const testConnectionBtn = document.getElementById('test-connection-btn');
const autoSyncInput = document.getElementById('auto-sync');
if (saveSettingsBtn) saveSettingsBtn.addEventListener('click', handleSaveSettings);
if (testConnectionBtn) testConnectionBtn.addEventListener('click', handleTestConnection);
if (autoSyncInput) {
autoSyncInput.addEventListener('change', () => updateSyncIntervalState());
}
// Time entries
const addEntryBtn = document.getElementById('add-entry-btn');
@@ -316,6 +320,14 @@ async function loadProjects() {
}
}
function selectProject(projectId) {
currentFilters = {
...currentFilters,
projectId: projectId || null,
};
switchView('entries');
}
let currentFilters = {
startDate: null,
endDate: null,
@@ -609,9 +621,13 @@ async function loadSettings() {
// Load current settings
const serverUrl = await storeGet('server_url') || '';
const apiToken = await storeGet('api_token') || '';
const autoSync = await storeGet('auto_sync');
const syncInterval = await storeGet('sync_interval');
const serverUrlInput = document.getElementById('settings-server-url');
const apiTokenInput = document.getElementById('settings-api-token');
const autoSyncInput = document.getElementById('auto-sync');
const syncIntervalInput = document.getElementById('sync-interval');
if (serverUrlInput) {
serverUrlInput.value = serverUrl;
@@ -621,17 +637,35 @@ async function loadSettings() {
apiTokenInput.value = apiToken ? '••••••••' : '';
apiTokenInput.dataset.hasToken = apiToken ? 'true' : 'false';
}
if (autoSyncInput) {
autoSyncInput.checked = autoSync !== null ? Boolean(autoSync) : true;
}
if (syncIntervalInput) {
syncIntervalInput.value = (syncInterval || 60).toString();
}
updateSyncIntervalState();
}
function updateSyncIntervalState() {
const autoSyncInput = document.getElementById('auto-sync');
const syncIntervalInput = document.getElementById('sync-interval');
if (!autoSyncInput || !syncIntervalInput) return;
syncIntervalInput.disabled = !autoSyncInput.checked;
}
async function handleSaveSettings() {
const serverUrlInput = document.getElementById('settings-server-url');
const apiTokenInput = document.getElementById('settings-api-token');
const autoSyncInput = document.getElementById('auto-sync');
const syncIntervalInput = document.getElementById('sync-interval');
const messageDiv = document.getElementById('settings-message');
if (!serverUrlInput || !apiTokenInput) return;
if (!serverUrlInput || !apiTokenInput || !autoSyncInput || !syncIntervalInput) return;
const serverUrl = serverUrlInput.value.trim();
const apiToken = apiTokenInput.value.trim();
const autoSync = autoSyncInput.checked;
const syncInterval = parseInt(syncIntervalInput.value, 10);
// Validate server URL
if (!serverUrl || !isValidUrl(serverUrl)) {
@@ -650,11 +684,18 @@ async function handleSaveSettings() {
showSettingsMessage('Please enter a valid API token (must start with tt_)', 'error');
return;
}
if (Number.isNaN(syncInterval) || syncInterval < 10) {
showSettingsMessage('Sync interval must be at least 10 seconds', 'error');
return;
}
// Save settings
try {
await storeSet('server_url', serverUrl);
await storeSet('api_token', finalApiToken);
await storeSet('auto_sync', autoSync);
await storeSet('sync_interval', syncInterval);
// Reinitialize API client with new settings
apiClient = new ApiClient(serverUrl);
@@ -799,6 +840,9 @@ async function loadProjectsForFilter() {
if (select) {
select.innerHTML = '<option value="">All Projects</option>' +
projects.map(p => `<option value="${p.id}">${p.name}</option>`).join('');
if (currentFilters.projectId) {
select.value = String(currentFilters.projectId);
}
}
} catch (error) {
console.error('Error loading projects for filter:', error);