feat: move projects to sidebar rail and speed up session switching (#506)

* feat: move projects from header tabs to left sidebar rail

* refactor: remove variant from git generation session context

* feat: implemented drandrop action for navrails

* refactor: improve sidebar drag-and-drop smoothness and remove floating overlay

* fix: prevent mobile nav rail touch from closing drawer and opening menu

* fix: hide header tabs on desktop

* fix: prevent session flicker when switching projects

* style: soften chat panel divider borders

* style: improve icon contrast across core navigation

* fix: stabilize session selection during project switching

* style: unify sidebar surfaces and transparent section layers

* style: remove UI shadows and keep only scroll shadow

* perf: speed up project switching with cached session loading

* perf: speed up Git changes view and background refresh

* perf: make session switching lighter and less aggressive

* perf: optimized sessions list loading while project switching

* perf: smooth chat rendering and reduce interaction spikes

* fix: restore reliable load older messages visibility
This commit is contained in:
Bohdan Triapitsyn
2026-02-25 14:32:23 +02:00
committed by GitHub
parent 4c69bccf56
commit 10851bd7ac
51 changed files with 1995 additions and 1399 deletions
+22 -1
View File
@@ -45,6 +45,19 @@ const normalizePath = (value?: string | null): string | null => {
return replaced.length > 1 ? replaced.replace(/\/+$/, "") : replaced;
};
const sessionChoiceAnalysisSignature = new Map<string, string>();
const ENABLE_ACTIVE_SESSION_TRIM = false;
const buildSessionChoiceAnalysisSignature = (messages: Array<{ info: Message; parts: Part[] }>): string => {
const lastMessage = messages[messages.length - 1];
const lastMessageId = typeof lastMessage?.info?.id === 'string' ? lastMessage.info.id : '';
const lastAssistant = [...messages]
.reverse()
.find((message) => message.info?.role === 'assistant');
const lastAssistantId = typeof lastAssistant?.info?.id === 'string' ? lastAssistant.info.id : '';
return `${messages.length}:${lastMessageId}:${lastAssistantId}`;
};
const resolveSessionDirectory = (
sessions: Session[],
sessionId: string | null | undefined,
@@ -319,7 +332,9 @@ export const useSessionStore = create<SessionStore>()(
await get().loadMessages(id);
}
get().trimToViewportWindow(id, getMessageLimit());
if (ENABLE_ACTIVE_SESSION_TRIM) {
get().trimToViewportWindow(id, getMessageLimit());
}
// Analyze session messages to extract agent/model/variant choices
// This ensures context is available even when ModelControls isn't mounted
@@ -327,12 +342,18 @@ export const useSessionStore = create<SessionStore>()(
if (sessionMessages && sessionMessages.length > 0) {
const agents = useConfigStore.getState().agents;
if (agents.length > 0) {
const analysisSignature = buildSessionChoiceAnalysisSignature(sessionMessages);
if (sessionChoiceAnalysisSignature.get(id) === analysisSignature) {
get().evictLeastRecentlyUsed();
return;
}
try {
await useContextStore.getState().analyzeAndSaveExternalSessionChoices(
id,
agents,
get().messages
);
sessionChoiceAnalysisSignature.set(id, analysisSignature);
} catch (error) {
console.warn('Failed to analyze session choices:', error);
}