personal memory agent
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

convey/settings: migrate saveField autosave to wave 0 primitives (wave 2)

Split settings autosave into timezone, env-key, and standard control branches. Keep field-local status surfaces while routing normal controls through saveControl and env keys through direct apiJson saves.

+95 -44
+95 -44
apps/settings/workspace.html
··· 3347 3347 updateEnvStatus('field-env-anthropic', env.ANTHROPIC_API_KEY, sysEnv.ANTHROPIC_API_KEY); 3348 3348 updateEnvStatus('field-env-revai', env.REVAI_ACCESS_TOKEN, sysEnv.REVAI_ACCESS_TOKEN); 3349 3349 updateEnvStatus('field-env-plaud', env.PLAUD_ACCESS_TOKEN, sysEnv.PLAUD_ACCESS_TOKEN); 3350 + 3351 + document.querySelectorAll('[data-section][data-key]').forEach((el) => { 3352 + el.__lastKnownValue = readAutoSaveControlValue(el); 3353 + }); 3350 3354 } 3351 3355 3352 3356 function updateEnvStatus(fieldId, isJournalConfigured, isSystemConfigured) { ··· 3416 3420 if (el) el.value = value; 3417 3421 } 3418 3422 3423 + function readAutoSaveControlValue(el) { 3424 + return el.type === 'checkbox' ? el.checked : el.value; 3425 + } 3426 + 3427 + function applySavedConfigResult(result, runtimeEnv) { 3428 + configData = result.config; 3429 + configData.runtime_env = runtimeEnv; 3430 + } 3431 + 3432 + async function saveConfigValue(section, key, value) { 3433 + const result = await window.apiJson('api/config', { 3434 + method: 'PUT', 3435 + headers: { 'Content-Type': 'application/json' }, 3436 + body: JSON.stringify({ section, data: { [key]: value } }) 3437 + }); 3438 + if (result.success) { 3439 + return result; 3440 + } 3441 + throw new Error(result.error || 'Save failed'); 3442 + } 3443 + 3444 + function applyEnvSaveEffects(el, key, result) { 3445 + el.value = ''; 3446 + if (result.key_validation) { 3447 + keyValidationData = result.key_validation; 3448 + configData.providers = configData.providers || {}; 3449 + configData.providers.key_validation = keyValidationData; 3450 + } 3451 + updateEnvStatus( 3452 + el.id, 3453 + configData?.env?.[key], 3454 + configData?.runtime_env?.[key] 3455 + ); 3456 + if (providersData) { 3457 + providersData.key_validation = keyValidationData; 3458 + for (const type of ['generate', 'cogitate']) { 3459 + const providerSelect = document.getElementById(`field-${type}-provider`); 3460 + if (providerSelect) { 3461 + updateTypeProviderKeyWarning( 3462 + type, 3463 + providerSelect.value, 3464 + providersData.api_keys || {}, 3465 + providersData.auth || {} 3466 + ); 3467 + } 3468 + } 3469 + } 3470 + } 3471 + 3419 3472 // ========== GENERIC FIELD SAVING ========== 3420 3473 function setupAutoSave() { 3421 3474 document.querySelectorAll('[data-section][data-key]').forEach(el => { ··· 3460 3513 clearTimeout(saveTimeouts.get(timeoutKey)); 3461 3514 saveTimeouts.set(timeoutKey, setTimeout(async () => { 3462 3515 saveTimeouts.delete(timeoutKey); 3463 - try { 3464 - const runtimeEnv = configData?.runtime_env || {}; 3465 - const response = await fetch('api/config', { 3466 - method: 'PUT', 3467 - headers: { 'Content-Type': 'application/json' }, 3468 - body: JSON.stringify({ section, data: { [key]: value } }) 3469 - }); 3470 - const result = await response.json(); 3471 - if (result.success) { 3472 - configData = result.config; 3473 - configData.runtime_env = runtimeEnv; 3474 - if (el) showFieldStatus(el, 'saved'); 3516 + const runtimeEnv = configData?.runtime_env || {}; 3517 + 3518 + if (!el) { 3519 + try { 3520 + const result = await saveConfigValue(section, key, value); 3521 + applySavedConfigResult(result, runtimeEnv); 3522 + } catch (err) { 3523 + window.logError(err, { context: `settings: saveField(${section}.${key}) failed` }); 3524 + } 3525 + return; 3526 + } 3475 3527 3476 - // For env fields, clear the input and update status indicator 3477 - if (el && section === 'env') { 3478 - el.value = ''; 3479 - if (result.key_validation) { 3480 - keyValidationData = result.key_validation; 3481 - configData.providers = configData.providers || {}; 3482 - configData.providers.key_validation = keyValidationData; 3483 - } 3484 - updateEnvStatus( 3485 - el.id, 3486 - configData?.env?.[key], 3487 - configData?.runtime_env?.[key] 3488 - ); 3489 - if (providersData) { 3490 - providersData.key_validation = keyValidationData; 3491 - for (const type of ['generate', 'cogitate']) { 3492 - const providerSelect = document.getElementById(`field-${type}-provider`); 3493 - if (providerSelect) { 3494 - updateTypeProviderKeyWarning( 3495 - type, 3496 - providerSelect.value, 3497 - providersData.api_keys || {}, 3498 - providersData.auth || {} 3499 - ); 3500 - } 3501 - } 3502 - } 3528 + if (section === 'env') { 3529 + const errorHost = prepareFieldErrorHost(el); 3530 + try { 3531 + const result = await saveConfigValue(section, key, value); 3532 + applySavedConfigResult(result, runtimeEnv); 3533 + applyEnvSaveEffects(el, key, result); 3534 + showFieldStatus(el, 'saved'); 3535 + } catch (err) { 3536 + const message = err?.serverMessage || err?.message || 'Save failed'; 3537 + if (errorHost) { 3538 + errorHost.innerHTML = `<span data-control-save-error class="control-save-error">${escapeHtml(message)}</span>`; 3503 3539 } 3504 - } else { 3505 - throw new Error(result.error); 3540 + window.logError(err, { context: `settings: saveField(env.${key}) failed` }); 3506 3541 } 3507 - } catch (err) { 3508 - console.error('Save error:', err); 3509 - if (el) showFieldStatus(el, 'error', err.message); 3542 + return; 3543 + } 3544 + 3545 + const errorHost = prepareFieldErrorHost(el); 3546 + try { 3547 + await window.saveControl({ 3548 + el, 3549 + errorHost, 3550 + revertOnError: true, 3551 + readValue: () => el.__lastKnownValue, 3552 + fetchArgs: () => saveConfigValue(section, key, value), 3553 + onSuccess: (result) => { 3554 + applySavedConfigResult(result, runtimeEnv); 3555 + el.__lastKnownValue = readAutoSaveControlValue(el); 3556 + showFieldStatus(el, 'saved'); 3557 + }, 3558 + onError: (err) => window.logError(err, { context: `settings: saveField(${section}.${key}) failed` }), 3559 + }); 3560 + } catch (_) { 3510 3561 } 3511 3562 }, 500)); 3512 3563 }