mirror of
https://github.com/siteboon/claudecodeui.git
synced 2026-02-28 11:37:39 +00:00
feat: persist active tab across reloads via localStorage (#414)
* feat: persist active tab across reloads via localStorage (closes #387) Remember the last active tab in localStorage instead of always resetting to 'chat'. Also stop force-switching to chat tab on session change, so users stay on their preferred tab (shell, git, etc.). * fix: validate localStorage tab value and add try-catch for restricted contexts Address CodeRabbit feedback: validate stored activeTab against known tab IDs before using it, and wrap localStorage access in try-catch to prevent crashes in restricted environments.
This commit is contained in:
@@ -101,6 +101,20 @@ const isUpdateAdditive = (
|
||||
);
|
||||
};
|
||||
|
||||
const VALID_TABS: Set<string> = new Set(['chat', 'files', 'shell', 'git', 'tasks', 'preview']);
|
||||
|
||||
const readPersistedTab = (): AppTab => {
|
||||
try {
|
||||
const stored = localStorage.getItem('activeTab');
|
||||
if (stored && VALID_TABS.has(stored)) {
|
||||
return stored as AppTab;
|
||||
}
|
||||
} catch {
|
||||
// localStorage unavailable
|
||||
}
|
||||
return 'chat';
|
||||
};
|
||||
|
||||
export function useProjectsState({
|
||||
sessionId,
|
||||
navigate,
|
||||
@@ -111,7 +125,16 @@ export function useProjectsState({
|
||||
const [projects, setProjects] = useState<Project[]>([]);
|
||||
const [selectedProject, setSelectedProject] = useState<Project | null>(null);
|
||||
const [selectedSession, setSelectedSession] = useState<ProjectSession | null>(null);
|
||||
const [activeTab, setActiveTab] = useState<AppTab>('chat');
|
||||
const [activeTab, setActiveTab] = useState<AppTab>(readPersistedTab);
|
||||
|
||||
useEffect(() => {
|
||||
try {
|
||||
localStorage.setItem('activeTab', activeTab);
|
||||
} catch {
|
||||
// Silently ignore storage errors
|
||||
}
|
||||
}, [activeTab]);
|
||||
|
||||
const [sidebarOpen, setSidebarOpen] = useState(false);
|
||||
const [isLoadingProjects, setIsLoadingProjects] = useState(true);
|
||||
const [loadingProgress, setLoadingProgress] = useState<LoadingProgress | null>(null);
|
||||
@@ -265,8 +288,6 @@ export function useProjectsState({
|
||||
return;
|
||||
}
|
||||
|
||||
const shouldSwitchTab = !selectedSession || selectedSession.id !== sessionId;
|
||||
|
||||
for (const project of projects) {
|
||||
const claudeSession = project.sessions?.find((session) => session.id === sessionId);
|
||||
if (claudeSession) {
|
||||
@@ -280,9 +301,6 @@ export function useProjectsState({
|
||||
if (shouldUpdateSession) {
|
||||
setSelectedSession({ ...claudeSession, __provider: 'claude' });
|
||||
}
|
||||
if (shouldSwitchTab) {
|
||||
setActiveTab('chat');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -298,9 +316,6 @@ export function useProjectsState({
|
||||
if (shouldUpdateSession) {
|
||||
setSelectedSession({ ...cursorSession, __provider: 'cursor' });
|
||||
}
|
||||
if (shouldSwitchTab) {
|
||||
setActiveTab('chat');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -316,9 +331,6 @@ export function useProjectsState({
|
||||
if (shouldUpdateSession) {
|
||||
setSelectedSession({ ...codexSession, __provider: 'codex' });
|
||||
}
|
||||
if (shouldSwitchTab) {
|
||||
setActiveTab('chat');
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -341,7 +353,7 @@ export function useProjectsState({
|
||||
(session: ProjectSession) => {
|
||||
setSelectedSession(session);
|
||||
|
||||
if (activeTab !== 'git' && activeTab !== 'preview') {
|
||||
if (activeTab === 'tasks' || activeTab === 'preview') {
|
||||
setActiveTab('chat');
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user