mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-02-14 02:42:04 +08:00
feat: 优化工作区索引状态刷新,增强头部徽章更新逻辑
This commit is contained in:
@@ -24,22 +24,46 @@ function escapeHtml(str) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Refresh workspace index status (FTS and Vector coverage)
|
* Refresh workspace index status (FTS and Vector coverage)
|
||||||
|
* Updates both the detailed panel (if exists) and header badges
|
||||||
*/
|
*/
|
||||||
async function refreshWorkspaceIndexStatus() {
|
async function refreshWorkspaceIndexStatus() {
|
||||||
var container = document.getElementById('workspaceIndexStatusContent');
|
var container = document.getElementById('workspaceIndexStatusContent');
|
||||||
if (!container) return;
|
var headerFtsEl = document.getElementById('headerFtsPercent');
|
||||||
|
var headerVectorEl = document.getElementById('headerVectorPercent');
|
||||||
|
|
||||||
// Show loading state
|
// If neither container nor header elements exist, nothing to update
|
||||||
|
if (!container && !headerFtsEl) return;
|
||||||
|
|
||||||
|
// Show loading state in container
|
||||||
|
if (container) {
|
||||||
container.innerHTML = '<div class="text-xs text-muted-foreground text-center py-2">' +
|
container.innerHTML = '<div class="text-xs text-muted-foreground text-center py-2">' +
|
||||||
'<i data-lucide="loader-2" class="w-4 h-4 animate-spin inline mr-1"></i> ' + (t('common.loading') || 'Loading...') +
|
'<i data-lucide="loader-2" class="w-4 h-4 animate-spin inline mr-1"></i> ' + (t('common.loading') || 'Loading...') +
|
||||||
'</div>';
|
'</div>';
|
||||||
if (window.lucide) lucide.createIcons();
|
if (window.lucide) lucide.createIcons();
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var response = await fetch('/api/codexlens/workspace-status');
|
var response = await fetch('/api/codexlens/workspace-status');
|
||||||
var result = await response.json();
|
var result = await response.json();
|
||||||
|
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
|
var ftsPercent = result.hasIndex ? (result.fts.percent || 0) : 0;
|
||||||
|
var vectorPercent = result.hasIndex ? (result.vector.percent || 0) : 0;
|
||||||
|
|
||||||
|
// Update header badges (always update if elements exist)
|
||||||
|
if (headerFtsEl) {
|
||||||
|
headerFtsEl.textContent = ftsPercent + '%';
|
||||||
|
headerFtsEl.className = 'text-sm font-medium ' +
|
||||||
|
(ftsPercent >= 100 ? 'text-success' : (ftsPercent > 0 ? 'text-blue-500' : 'text-muted-foreground'));
|
||||||
|
}
|
||||||
|
if (headerVectorEl) {
|
||||||
|
headerVectorEl.textContent = vectorPercent.toFixed(1) + '%';
|
||||||
|
headerVectorEl.className = 'text-sm font-medium ' +
|
||||||
|
(vectorPercent >= 100 ? 'text-success' : (vectorPercent >= 50 ? 'text-purple-500' : (vectorPercent > 0 ? 'text-purple-400' : 'text-muted-foreground')));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update detailed container (if exists)
|
||||||
|
if (container) {
|
||||||
var html = '';
|
var html = '';
|
||||||
|
|
||||||
if (!result.hasIndex) {
|
if (!result.hasIndex) {
|
||||||
@@ -55,7 +79,6 @@ async function refreshWorkspaceIndexStatus() {
|
|||||||
'</div>';
|
'</div>';
|
||||||
} else {
|
} else {
|
||||||
// FTS Status
|
// FTS Status
|
||||||
var ftsPercent = result.fts.percent || 0;
|
|
||||||
var ftsColor = ftsPercent >= 100 ? 'bg-success' : (ftsPercent > 0 ? 'bg-blue-500' : 'bg-muted-foreground');
|
var ftsColor = ftsPercent >= 100 ? 'bg-success' : (ftsPercent > 0 ? 'bg-blue-500' : 'bg-muted-foreground');
|
||||||
var ftsTextColor = ftsPercent >= 100 ? 'text-success' : (ftsPercent > 0 ? 'text-blue-500' : 'text-muted-foreground');
|
var ftsTextColor = ftsPercent >= 100 ? 'text-success' : (ftsPercent > 0 ? 'text-blue-500' : 'text-muted-foreground');
|
||||||
|
|
||||||
@@ -76,7 +99,6 @@ async function refreshWorkspaceIndexStatus() {
|
|||||||
'</div>';
|
'</div>';
|
||||||
|
|
||||||
// Vector Status
|
// Vector Status
|
||||||
var vectorPercent = result.vector.percent || 0;
|
|
||||||
var vectorColor = vectorPercent >= 100 ? 'bg-success' : (vectorPercent >= 50 ? 'bg-purple-500' : (vectorPercent > 0 ? 'bg-purple-400' : 'bg-muted-foreground'));
|
var vectorColor = vectorPercent >= 100 ? 'bg-success' : (vectorPercent >= 50 ? 'bg-purple-500' : (vectorPercent > 0 ? 'bg-purple-400' : 'bg-muted-foreground'));
|
||||||
var vectorTextColor = vectorPercent >= 100 ? 'text-success' : (vectorPercent >= 50 ? 'text-purple-500' : (vectorPercent > 0 ? 'text-purple-400' : 'text-muted-foreground'));
|
var vectorTextColor = vectorPercent >= 100 ? 'text-success' : (vectorPercent >= 50 ? 'text-purple-500' : (vectorPercent > 0 ? 'text-purple-400' : 'text-muted-foreground'));
|
||||||
|
|
||||||
@@ -112,19 +134,29 @@ async function refreshWorkspaceIndexStatus() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
container.innerHTML = html;
|
container.innerHTML = html;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// Error from API
|
||||||
|
if (headerFtsEl) headerFtsEl.textContent = '--';
|
||||||
|
if (headerVectorEl) headerVectorEl.textContent = '--';
|
||||||
|
if (container) {
|
||||||
container.innerHTML = '<div class="text-xs text-destructive text-center py-2">' +
|
container.innerHTML = '<div class="text-xs text-destructive text-center py-2">' +
|
||||||
'<i data-lucide="alert-circle" class="w-4 h-4 inline mr-1"></i> ' +
|
'<i data-lucide="alert-circle" class="w-4 h-4 inline mr-1"></i> ' +
|
||||||
(result.error || t('common.error') || 'Error loading status') +
|
(result.error || t('common.error') || 'Error loading status') +
|
||||||
'</div>';
|
'</div>';
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('[CodexLens] Failed to load workspace status:', err);
|
console.error('[CodexLens] Failed to load workspace status:', err);
|
||||||
|
if (headerFtsEl) headerFtsEl.textContent = '--';
|
||||||
|
if (headerVectorEl) headerVectorEl.textContent = '--';
|
||||||
|
if (container) {
|
||||||
container.innerHTML = '<div class="text-xs text-destructive text-center py-2">' +
|
container.innerHTML = '<div class="text-xs text-destructive text-center py-2">' +
|
||||||
'<i data-lucide="alert-circle" class="w-4 h-4 inline mr-1"></i> ' +
|
'<i data-lucide="alert-circle" class="w-4 h-4 inline mr-1"></i> ' +
|
||||||
(t('common.error') || 'Error') + ': ' + err.message +
|
(t('common.error') || 'Error') + ': ' + err.message +
|
||||||
'</div>';
|
'</div>';
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (window.lucide) lucide.createIcons();
|
if (window.lucide) lucide.createIcons();
|
||||||
}
|
}
|
||||||
@@ -3884,32 +3916,45 @@ async function renderCodexLensManager() {
|
|||||||
// Load additional data in parallel (non-blocking)
|
// Load additional data in parallel (non-blocking)
|
||||||
var isInstalled = window.cliToolsStatus?.codexlens?.installed || dashboardData?.installed;
|
var isInstalled = window.cliToolsStatus?.codexlens?.installed || dashboardData?.installed;
|
||||||
|
|
||||||
|
// OPTIMIZATION: Load critical status first (workspace index status for header badges)
|
||||||
|
// This is prioritized as it updates the visible header immediately
|
||||||
|
if (isInstalled) {
|
||||||
|
refreshWorkspaceIndexStatus(); // Updates header FTS/Vector badges
|
||||||
|
}
|
||||||
|
|
||||||
// Wait for LiteLLM config before loading semantic deps (it may need provider info)
|
// Wait for LiteLLM config before loading semantic deps (it may need provider info)
|
||||||
await litellmPromise;
|
await litellmPromise;
|
||||||
|
|
||||||
// Load FastEmbed installation status (show/hide install card)
|
// OPTIMIZATION: Batch non-critical loads with requestIdleCallback or setTimeout
|
||||||
loadFastEmbedInstallStatus();
|
// This prevents blocking the main thread and allows smoother UI updates
|
||||||
|
var deferredLoads = function() {
|
||||||
// Always load semantic deps status - it needs GPU detection and device list
|
// Load all independent status checks in parallel
|
||||||
// which are not included in the aggregated endpoint
|
Promise.all([
|
||||||
loadSemanticDepsStatus();
|
// FastEmbed and semantic deps status (independent)
|
||||||
|
Promise.resolve().then(function() { loadFastEmbedInstallStatus(); }),
|
||||||
loadModelList();
|
Promise.resolve().then(function() { loadSemanticDepsStatus(); }),
|
||||||
loadRerankerModelList();
|
// Model lists (independent)
|
||||||
|
Promise.resolve().then(function() { loadModelList(); }),
|
||||||
// Initialize model mode and semantic status badge
|
Promise.resolve().then(function() { loadRerankerModelList(); }),
|
||||||
|
// File watcher status (independent)
|
||||||
|
Promise.resolve().then(function() { initWatcherStatus(); })
|
||||||
|
]).then(function() {
|
||||||
|
// After all loads complete, update the semantic status badge
|
||||||
updateSemanticStatusBadge();
|
updateSemanticStatusBadge();
|
||||||
|
});
|
||||||
|
|
||||||
// Initialize file watcher status
|
// Load index stats if installed (independent from above)
|
||||||
initWatcherStatus();
|
|
||||||
|
|
||||||
// Load index stats for the Index Manager section
|
|
||||||
if (isInstalled) {
|
if (isInstalled) {
|
||||||
loadIndexStatsForPage();
|
loadIndexStatsForPage();
|
||||||
// Check index health based on git history
|
|
||||||
checkIndexHealth();
|
checkIndexHealth();
|
||||||
// Load workspace index status (FTS and Vector coverage)
|
}
|
||||||
refreshWorkspaceIndexStatus();
|
};
|
||||||
|
|
||||||
|
// Use requestIdleCallback for deferred loads if available, otherwise use setTimeout
|
||||||
|
if (typeof requestIdleCallback === 'function') {
|
||||||
|
requestIdleCallback(deferredLoads, { timeout: 500 });
|
||||||
|
} else {
|
||||||
|
setTimeout(deferredLoads, 50);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
container.innerHTML = '<div class="text-center py-12 text-destructive"><i data-lucide="alert-circle" class="w-8 h-8 mx-auto mb-2"></i><p>' + t('common.error') + ': ' + escapeHtml(err.message) + '</p></div>';
|
container.innerHTML = '<div class="text-center py-12 text-destructive"><i data-lucide="alert-circle" class="w-8 h-8 mx-auto mb-2"></i><p>' + t('common.error') + ': ' + escapeHtml(err.message) + '</p></div>';
|
||||||
@@ -3946,6 +3991,21 @@ function buildCodexLensManagerPage(config) {
|
|||||||
'<span class="text-sm text-muted-foreground">' + t('codexlens.indexes') + ':</span>' +
|
'<span class="text-sm text-muted-foreground">' + t('codexlens.indexes') + ':</span>' +
|
||||||
'<span class="text-lg font-bold text-primary">' + indexCount + '</span>' +
|
'<span class="text-lg font-bold text-primary">' + indexCount + '</span>' +
|
||||||
'</div>' +
|
'</div>' +
|
||||||
|
// Workspace Index Status badges (FTS/Vector percentages)
|
||||||
|
(isInstalled
|
||||||
|
? '<div id="headerIndexStatusContainer" class="flex items-center gap-2">' +
|
||||||
|
'<div class="flex items-center gap-1.5 px-2.5 py-1 rounded-lg bg-blue-500/10 border border-blue-500/20" title="' + (t('codexlens.ftsIndex') || 'FTS Index') + '">' +
|
||||||
|
'<i data-lucide="file-text" class="w-3.5 h-3.5 text-blue-500"></i>' +
|
||||||
|
'<span class="text-xs text-muted-foreground">FTS:</span>' +
|
||||||
|
'<span id="headerFtsPercent" class="text-sm font-medium text-blue-500">--</span>' +
|
||||||
|
'</div>' +
|
||||||
|
'<div class="flex items-center gap-1.5 px-2.5 py-1 rounded-lg bg-purple-500/10 border border-purple-500/20" title="' + (t('codexlens.vectorIndex') || 'Vector Index') + '">' +
|
||||||
|
'<i data-lucide="brain" class="w-3.5 h-3.5 text-purple-500"></i>' +
|
||||||
|
'<span class="text-xs text-muted-foreground">Vector:</span>' +
|
||||||
|
'<span id="headerVectorPercent" class="text-sm font-medium text-purple-500">--</span>' +
|
||||||
|
'</div>' +
|
||||||
|
'</div>'
|
||||||
|
: '') +
|
||||||
'</div>' +
|
'</div>' +
|
||||||
'</div>' +
|
'</div>' +
|
||||||
'</div>' +
|
'</div>' +
|
||||||
|
|||||||
Reference in New Issue
Block a user