From 777d5df57356c3d65190e0b769d24ca0e4e1268b Mon Sep 17 00:00:00 2001 From: catlog22 Date: Thu, 25 Dec 2025 17:22:42 +0800 Subject: [PATCH] feat: Add aggregated endpoint for CodexLens dashboard initialization and improve loading performance --- .../dashboard-js/components/cli-status.js | 48 +++++++++++ .../dashboard-js/views/codexlens-manager.js | 83 ++++++++++++++----- 2 files changed, 110 insertions(+), 21 deletions(-) diff --git a/ccw/src/templates/dashboard-js/components/cli-status.js b/ccw/src/templates/dashboard-js/components/cli-status.js index 3f99e7f2..f1f448c1 100644 --- a/ccw/src/templates/dashboard-js/components/cli-status.js +++ b/ccw/src/templates/dashboard-js/components/cli-status.js @@ -129,6 +129,54 @@ async function loadCodexLensStatus() { } } +/** + * Load CodexLens dashboard data using aggregated endpoint (single API call) + * This is optimized for the CodexLens Manager page initialization + * @returns {Promise} Dashboard init data or null on error + */ +async function loadCodexLensDashboardInit() { + try { + const response = await fetch('/api/codexlens/dashboard-init'); + if (!response.ok) throw new Error('Failed to load CodexLens dashboard init'); + const data = await response.json(); + + // Update status variables from aggregated response + codexLensStatus = data.status || { ready: false }; + semanticStatus = data.semantic || { available: false }; + + // Expose to window for other modules + if (!window.cliToolsStatus) { + window.cliToolsStatus = {}; + } + window.cliToolsStatus.codexlens = { + installed: data.installed || false, + version: data.status?.version || null, + installedModels: [], + config: data.config || {}, + semantic: data.semantic || {} + }; + + // Store config globally for easy access + window.codexLensConfig = data.config || {}; + window.codexLensStatusData = data.statusData || {}; + + // Update badges + updateCodexLensBadge(); + + console.log('[CLI Status] CodexLens dashboard init loaded:', { + installed: data.installed, + version: data.status?.version, + semanticAvailable: data.semantic?.available + }); + + return data; + } catch (err) { + console.error('Failed to load CodexLens dashboard init:', err); + // Fallback to individual calls + return await loadCodexLensStatus(); + } +} + /** * Legacy: Load semantic status individually */ diff --git a/ccw/src/templates/dashboard-js/views/codexlens-manager.js b/ccw/src/templates/dashboard-js/views/codexlens-manager.js index 44cec49f..34a36ba9 100644 --- a/ccw/src/templates/dashboard-js/views/codexlens-manager.js +++ b/ccw/src/templates/dashboard-js/views/codexlens-manager.js @@ -1904,37 +1904,64 @@ async function renderCodexLensManager() { container.innerHTML = '
' + t('common.loading') + '
'; try { - // Load CodexLens status first to populate window.cliToolsStatus.codexlens - if (typeof loadCodexLensStatus === 'function') { - await loadCodexLensStatus(); - } + // Use aggregated endpoint for faster page load (single API call) + var dashboardData = null; + var config = { index_dir: '~/.codexlens/indexes', index_count: 0 }; - // Load LiteLLM API config for embedding backend options - try { - console.log('[CodexLens] Loading LiteLLM config...'); - var litellmResponse = await fetch('/api/litellm-api/config'); - console.log('[CodexLens] LiteLLM response status:', litellmResponse.status); - if (litellmResponse.ok) { - window.litellmApiConfig = await litellmResponse.json(); - console.log('[CodexLens] LiteLLM config loaded:', window.litellmApiConfig); - console.log('[CodexLens] Providers:', window.litellmApiConfig?.providers?.length || 0); - } else { - console.warn('[CodexLens] LiteLLM config response not ok:', litellmResponse.status); + if (typeof loadCodexLensDashboardInit === 'function') { + console.log('[CodexLens] Using aggregated dashboard-init endpoint...'); + dashboardData = await loadCodexLensDashboardInit(); + if (dashboardData && dashboardData.config) { + config = dashboardData.config; + console.log('[CodexLens] Dashboard init loaded, config:', config); } - } catch (e) { - console.warn('[CodexLens] Could not load LiteLLM config:', e); + } else if (typeof loadCodexLensStatus === 'function') { + // Fallback to legacy individual calls + console.log('[CodexLens] Fallback to legacy loadCodexLensStatus...'); + await loadCodexLensStatus(); + var response = await fetch('/api/codexlens/config'); + config = await response.json(); } - var response = await fetch('/api/codexlens/config'); - var config = await response.json(); + // Load LiteLLM API config for embedding backend options (parallel with page render) + var litellmPromise = (async () => { + try { + console.log('[CodexLens] Loading LiteLLM config...'); + var litellmResponse = await fetch('/api/litellm-api/config'); + if (litellmResponse.ok) { + window.litellmApiConfig = await litellmResponse.json(); + console.log('[CodexLens] LiteLLM config loaded, providers:', window.litellmApiConfig?.providers?.length || 0); + } + } catch (e) { + console.warn('[CodexLens] Could not load LiteLLM config:', e); + } + })(); container.innerHTML = buildCodexLensManagerPage(config); if (window.lucide) lucide.createIcons(); initCodexLensManagerPageEvents(config); - loadSemanticDepsStatus(); + + // Load additional data in parallel (non-blocking) + var isInstalled = window.cliToolsStatus?.codexlens?.installed || dashboardData?.installed; + + // Wait for LiteLLM config before loading semantic deps (it may need provider info) + await litellmPromise; + + // Load semantic deps status (skip if we already have it from dashboard-init) + if (!dashboardData?.semantic) { + loadSemanticDepsStatus(); + } else { + // Use cached semantic status from dashboard-init + var semanticContainer = document.getElementById('semanticDepsStatus'); + if (semanticContainer && dashboardData.semantic) { + updateSemanticDepsUI(semanticContainer, dashboardData.semantic); + } + } + loadModelList(); + // Load index stats for the Index Manager section - if (window.cliToolsStatus?.codexlens?.installed) { + if (isInstalled) { loadIndexStatsForPage(); } } catch (err) { @@ -1943,6 +1970,20 @@ async function renderCodexLensManager() { } } +/** + * Update semantic deps UI from cached data + */ +function updateSemanticDepsUI(container, semanticData) { + if (!container) return; + + if (semanticData.available) { + container.innerHTML = '
' + (semanticData.backend || 'Ready') + '
'; + } else { + container.innerHTML = '
' + t('codexlens.notInstalled') + '
'; + } + if (window.lucide) lucide.createIcons(); +} + /** * Build CodexLens Manager page content */