From 6fc30ac75533d11b4491f6ff694a1c3cbeb7dae5 Mon Sep 17 00:00:00 2001 From: curo1305 Date: Tue, 23 Jun 2026 19:50:35 +0200 Subject: [PATCH] feat(14-08): add cache settings API/store wiring for Settings integration - Fix getCacheSettings/updateCacheSettings URLs to use /api/cloud/analysis/cache and /api/cloud/analysis/cache/settings (Rule 1: wrong URLs per Plan 14-03 backend) - Add loadCacheSettings action: hydrates tierCapBytes, cacheUsage, cacheLimit, detailedAnalysisProgress, failureBehavior from server without clearing on error - Add tierCapBytes, cacheUsage, cacheSettingsLoading, cacheSettingsError state - updateCacheSettings merges full CacheStatusOut response into local state --- frontend/src/api/cloud.js | 21 +++-- frontend/src/stores/cloudConnections.js | 116 ++++++++++++++++++++++-- 2 files changed, 125 insertions(+), 12 deletions(-) diff --git a/frontend/src/api/cloud.js b/frontend/src/api/cloud.js index ab81ad2..f21dfd0 100644 --- a/frontend/src/api/cloud.js +++ b/frontend/src/api/cloud.js @@ -354,19 +354,28 @@ export function retryAnalysisItem(jobId, itemId) { } /** - * Get the current user cache settings. + * Get the current user cache status and analysis settings. * - * Returns { cloud_cache_limit_bytes, ... } + * Returns CacheStatusOut: { entry_count, total_bytes, cache_limit_bytes, + * tier_cap_bytes, analysis_progress_detail, analysis_failure_behavior } + * + * Never includes object_key, credentials_enc, or raw provider URLs (T-14-02/T-14-08). */ export function getCacheSettings() { - return request('/api/users/me/settings') + return request('/api/cloud/analysis/cache') } /** - * Update the current user cache settings. + * Update the current user analysis settings and/or cache limit. * - * @param {{ cloud_cache_limit_bytes?: number }} params + * PATCH /api/cloud/analysis/cache/settings + * Body fields (all optional): cloud_cache_limit_bytes, analysis_progress_detail, + * analysis_failure_behavior. + * Returns fresh CacheStatusOut after update. + * + * @param {{ cloud_cache_limit_bytes?: number, analysis_progress_detail?: boolean, + * analysis_failure_behavior?: string }} params */ export function updateCacheSettings(params) { - return jsonRequest('/api/users/me/settings', 'PATCH', params) + return jsonRequest('/api/cloud/analysis/cache/settings', 'PATCH', params) } diff --git a/frontend/src/stores/cloudConnections.js b/frontend/src/stores/cloudConnections.js index d84c18a..2342da8 100644 --- a/frontend/src/stores/cloudConnections.js +++ b/frontend/src/stores/cloudConnections.js @@ -135,9 +135,34 @@ export const useCloudConnectionsStore = defineStore('cloudConnections', () => { /** * CACHE-04: User-configured cloud cache limit in bytes. * Default: 500 MB (500 * 1024 * 1024). + * Hydrated from server via loadCacheSettings — in-memory only, not persisted. */ const cacheLimit = ref(500 * 1024 * 1024) + /** + * Server-authoritative tier cap for the cache limit in bytes. + * Loaded from GET /api/cloud/analysis/cache (tier_cap_bytes field). + * null until loadCacheSettings has run. + */ + const tierCapBytes = ref(null) + + /** + * Current aggregate cache usage from the server. + * Loaded from GET /api/cloud/analysis/cache. + * { entry_count: number, total_bytes: number } — no object_key or credentials. + */ + const cacheUsage = ref(null) + + /** + * Whether the last loadCacheSettings call is in flight. + */ + const cacheSettingsLoading = ref(false) + + /** + * Validation/network error from the last settings call, or null. + */ + const cacheSettingsError = ref(null) + /** * D-12: Connection health state map — single source for both browser compact status * and Settings full diagnostics. @@ -525,17 +550,90 @@ export const useCloudConnectionsStore = defineStore('cloudConnections', () => { detailedAnalysisProgress.value = !!enabled } + /** + * CACHE-04: Load cache status and analysis settings from the server. + * + * Hydrates cacheLimit, tierCapBytes, cacheUsage, detailedAnalysisProgress, + * and failureBehavior from the authoritative backend state. + * + * Errors do not clear existing in-memory settings — cacheSettingsError is + * set so the UI can surface a controlled message. + */ + async function loadCacheSettings() { + cacheSettingsLoading.value = true + cacheSettingsError.value = null + try { + const result = await api.getCacheSettings() + // Hydrate server-authoritative values into local state + if (result?.cache_limit_bytes !== undefined) { + cacheLimit.value = result.cache_limit_bytes + } + if (result?.tier_cap_bytes !== undefined) { + tierCapBytes.value = result.tier_cap_bytes + } + if (result?.entry_count !== undefined || result?.total_bytes !== undefined) { + cacheUsage.value = { + entry_count: result.entry_count ?? 0, + total_bytes: result.total_bytes ?? 0, + } + } + if (result?.analysis_progress_detail !== undefined) { + detailedAnalysisProgress.value = !!result.analysis_progress_detail + } + if (result?.analysis_failure_behavior !== undefined) { + failureBehavior.value = result.analysis_failure_behavior + } + return result + } catch (e) { + // Do not clear existing settings on error — surface a controlled message + cacheSettingsError.value = e?.message ?? 'Failed to load cache settings' + return null + } finally { + cacheSettingsLoading.value = false + } + } + /** * CACHE-04: Update user cache settings via the API. * - * @param {{ cloud_cache_limit_bytes?: number }} params + * Merges server response back into local state after a successful update. + * Validation errors surface as a thrown error (caller responsible for display). + * + * @param {{ cloud_cache_limit_bytes?: number, analysis_progress_detail?: boolean, + * analysis_failure_behavior?: string }} params */ async function updateCacheSettings(params) { - const result = await api.updateCacheSettings(params) - if (result?.cloud_cache_limit_bytes !== undefined) { - cacheLimit.value = result.cloud_cache_limit_bytes + cacheSettingsError.value = null + try { + const result = await api.updateCacheSettings(params) + // Merge server response into local state + if (result?.cache_limit_bytes !== undefined) { + cacheLimit.value = result.cache_limit_bytes + } + if (result?.cloud_cache_limit_bytes !== undefined) { + cacheLimit.value = result.cloud_cache_limit_bytes + } + if (result?.tier_cap_bytes !== undefined) { + tierCapBytes.value = result.tier_cap_bytes + } + if (result?.entry_count !== undefined || result?.total_bytes !== undefined) { + cacheUsage.value = { + entry_count: result.entry_count ?? 0, + total_bytes: result.total_bytes ?? 0, + } + } + if (result?.analysis_progress_detail !== undefined) { + detailedAnalysisProgress.value = !!result.analysis_progress_detail + } + if (result?.analysis_failure_behavior !== undefined) { + failureBehavior.value = result.analysis_failure_behavior + } + return result + } catch (e) { + // Surface validation error without clearing existing settings + cacheSettingsError.value = e?.message ?? 'Failed to update cache settings' + throw e } - return result } return { @@ -591,9 +689,15 @@ export const useCloudConnectionsStore = defineStore('cloudConnections', () => { retryItem, skipItem, cancelItem, - // User preferences + // User preferences and cache settings setFailureBehavior, setDetailedAnalysisProgress, + loadCacheSettings, updateCacheSettings, + // Server-authoritative cache state + tierCapBytes, + cacheUsage, + cacheSettingsLoading, + cacheSettingsError, } })