Add loading progress indicator

Adds real-time progress feedback when loading projects:
- Server broadcasts progress updates via WebSocket
- Sidebar shows current project being loaded with progress bar
- Fixed progress counter to show correct current/total
- Completion event now fires after all projects (including manual) are processed
- Race condition fix for timeout cleanup using ref
- Added cleanup function to prevent state update on unmounted component
This commit is contained in:
Eric Blanquer​
2026-01-18 04:58:03 +01:00
parent f8d1ec7b9e
commit 9e03acb0db
4 changed files with 138 additions and 19 deletions

View File

@@ -80,6 +80,20 @@ import { validateApiKey, authenticateToken, authenticateWebSocket } from './midd
// File system watcher for projects folder
let projectsWatcher = null;
const connectedClients = new Set();
let isGetProjectsRunning = false; // Flag to prevent reentrant calls
// Broadcast progress to all connected WebSocket clients
function broadcastProgress(progress) {
const message = JSON.stringify({
type: 'loading_progress',
...progress
});
connectedClients.forEach(client => {
if (client.readyState === WebSocket.OPEN) {
client.send(message);
}
});
}
// Setup file system watcher for Claude projects folder using chokidar
async function setupProjectsWatcher() {
@@ -117,13 +131,19 @@ async function setupProjectsWatcher() {
const debouncedUpdate = async (eventType, filePath) => {
clearTimeout(debounceTimer);
debounceTimer = setTimeout(async () => {
// Prevent reentrant calls
if (isGetProjectsRunning) {
return;
}
try {
isGetProjectsRunning = true;
// Clear project directory cache when files change
clearProjectDirectoryCache();
// Get updated projects list
const updatedProjects = await getProjects();
const updatedProjects = await getProjects(broadcastProgress);
// Notify all connected clients about the project changes
const updateMessage = JSON.stringify({
@@ -142,6 +162,8 @@ async function setupProjectsWatcher() {
} catch (error) {
console.error('[ERROR] Error handling project changes:', error);
} finally {
isGetProjectsRunning = false;
}
}, 300); // 300ms debounce (slightly faster than before)
};
@@ -366,7 +388,7 @@ app.post('/api/system/update', authenticateToken, async (req, res) => {
app.get('/api/projects', authenticateToken, async (req, res) => {
try {
const projects = await getProjects();
const projects = await getProjects(broadcastProgress);
res.json(projects);
} catch (error) {
res.status(500).json({ error: error.message });