Fix tab persistence in Claude IDE - persist closed tabs to localStorage

Implement localStorage persistence for closed session and project tabs.
When users close tabs, they now remain closed after page refresh.

Changes:
- session-tabs.js: Add closedSessions tracking with localStorage
- project-manager.js: Add closedProjects tracking with localStorage
- Filter out closed tabs on load
- Persist state whenever tabs are closed

Fixes issue where closed tabs would reappear on page refresh.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
uroma
2026-01-22 12:40:31 +00:00
Unverified
parent fc76581337
commit b82837aa5f
2 changed files with 87 additions and 4 deletions

View File

@@ -22,6 +22,8 @@ class ProjectManager {
this.activeProjectId = null; this.activeProjectId = null;
this.activeSessionId = null; this.activeSessionId = null;
this.initialized = false; this.initialized = false;
this.closedProjects = new Set(); // Track closed project IDs
this.STORAGE_KEY = 'claude_ide_closed_projects';
} }
/** /**
@@ -31,6 +33,7 @@ class ProjectManager {
if (this.initialized) return; if (this.initialized) return;
console.log('[ProjectManager] Initializing...'); console.log('[ProjectManager] Initializing...');
this.loadClosedProjects();
await this.loadProjects(); await this.loadProjects();
this.renderProjectTabs(); this.renderProjectTabs();
this.initialized = true; this.initialized = true;
@@ -44,6 +47,36 @@ class ProjectManager {
console.log('[ProjectManager] Initialized with', this.projects.size, 'projects'); console.log('[ProjectManager] Initialized with', this.projects.size, 'projects');
} }
/**
* Load closed projects from localStorage
*/
loadClosedProjects() {
try {
const stored = localStorage.getItem(this.STORAGE_KEY);
if (stored) {
const closedIds = JSON.parse(stored);
this.closedProjects = new Set(closedIds);
console.log('[ProjectManager] Loaded', this.closedProjects.size, 'closed projects from storage');
}
} catch (error) {
console.error('[ProjectManager] Error loading closed projects:', error);
this.closedProjects = new Set();
}
}
/**
* Save closed projects to localStorage
*/
saveClosedProjects() {
try {
const closedIds = Array.from(this.closedProjects);
localStorage.setItem(this.STORAGE_KEY, JSON.stringify(closedIds));
console.log('[ProjectManager] Saved', closedIds.length, 'closed projects to storage');
} catch (error) {
console.error('[ProjectManager] Error saving closed projects:', error);
}
}
/** /**
* Load all sessions and organize them by project * Load all sessions and organize them by project
*/ */
@@ -97,8 +130,16 @@ class ProjectManager {
} }
}); });
this.projects = grouped; // Filter out closed projects
console.log('[ProjectManager] Loaded', this.projects.size, 'projects'); const filtered = new Map();
grouped.forEach((project, key) => {
if (!this.closedProjects.has(project.id)) {
filtered.set(key, project);
}
});
this.projects = filtered;
console.log('[ProjectManager] Loaded', this.projects.size, 'projects (filtered out', grouped.size - this.projects.size, 'closed)');
} catch (error) { } catch (error) {
console.error('[ProjectManager] Error loading projects:', error); console.error('[ProjectManager] Error loading projects:', error);
@@ -434,6 +475,10 @@ class ProjectManager {
console.log('[ProjectManager] Closing project:', projectId); console.log('[ProjectManager] Closing project:', projectId);
// Add to closed projects set and persist
this.closedProjects.add(projectId);
this.saveClosedProjects();
// Remove project from map // Remove project from map
this.projects.delete(projectKey); this.projects.delete(projectKey);

View File

@@ -21,6 +21,8 @@ class SessionTabs {
this.sessions = []; this.sessions = [];
this.activeSessionId = null; this.activeSessionId = null;
this.initialized = false; this.initialized = false;
this.closedSessions = new Set(); // Track closed session IDs
this.STORAGE_KEY = 'claude_ide_closed_sessions';
} }
/** /**
@@ -30,16 +32,48 @@ class SessionTabs {
if (this.initialized) return; if (this.initialized) return;
console.log('[SessionTabs] Initializing...'); console.log('[SessionTabs] Initializing...');
this.loadClosedSessions();
this.render(); this.render();
this.initialized = true; this.initialized = true;
} }
/**
* Load closed sessions from localStorage
*/
loadClosedSessions() {
try {
const stored = localStorage.getItem(this.STORAGE_KEY);
if (stored) {
const closedIds = JSON.parse(stored);
this.closedSessions = new Set(closedIds);
console.log('[SessionTabs] Loaded', this.closedSessions.size, 'closed sessions from storage');
}
} catch (error) {
console.error('[SessionTabs] Error loading closed sessions:', error);
this.closedSessions = new Set();
}
}
/**
* Save closed sessions to localStorage
*/
saveClosedSessions() {
try {
const closedIds = Array.from(this.closedSessions);
localStorage.setItem(this.STORAGE_KEY, JSON.stringify(closedIds));
console.log('[SessionTabs] Saved', closedIds.length, 'closed sessions to storage');
} catch (error) {
console.error('[SessionTabs] Error saving closed sessions:', error);
}
}
/** /**
* Set sessions for current project * Set sessions for current project
*/ */
setSessions(sessions) { setSessions(sessions) {
this.sessions = sessions || []; // Filter out closed sessions
console.log('[SessionTabs] Set', this.sessions.length, 'sessions'); this.sessions = (sessions || []).filter(s => !this.closedSessions.has(s.id));
console.log('[SessionTabs] Set', this.sessions.length, 'sessions (filtered out', (sessions || []).length - this.sessions.length, 'closed)');
} }
/** /**
@@ -191,6 +225,10 @@ class SessionTabs {
console.log('[SessionTabs] Closing session:', sessionId); console.log('[SessionTabs] Closing session:', sessionId);
// Add to closed sessions set and persist
this.closedSessions.add(sessionId);
this.saveClosedSessions();
// Note: This just removes the tab from view // Note: This just removes the tab from view
// The session still exists on the server // The session still exists on the server
this.sessions = this.sessions.filter(s => s.id !== sessionId); this.sessions = this.sessions.filter(s => s.id !== sessionId);