1- import { useState } from 'react' ;
1+ import { useState , useMemo } from 'react' ;
22import { useGlobalStore } from '../stores/global.store' ;
3- import { API_BASE , api } from '../lib/api' ;
4- import type { Thread } from '@shared/types' ;
3+ import { api } from '../lib/api' ;
54
65function normalizeCwd ( p : string ) : string {
76 return p . replace ( / \\ / g, '/' ) . replace ( / ^ ( [ A - Z ] ) : / , ( _ , l : string ) => `${ l . toLowerCase ( ) } :` ) ;
@@ -17,25 +16,24 @@ function relativeTime(ts: number): string {
1716 return `${ Math . floor ( days / 7 ) } 周` ;
1817}
1918
20- function getProjectThreads ( threads : Record < string , Thread > , rootPath : string ) : Thread [ ] {
21- const normalizedRoot = normalizeCwd ( rootPath ) ;
22- return Object . values ( threads )
23- . filter ( ( t ) => {
24- const tcwd = normalizeCwd ( t . cwd ) ;
25- return tcwd . startsWith ( normalizedRoot ) ;
26- } )
27- . sort ( ( a , b ) => b . updatedAt - a . updatedAt ) ;
28- }
29-
3019export default function AgentSidebar ( ) {
3120 const sidebarCollapsed = useGlobalStore ( ( s ) => s . ui . sidebarCollapsed ) ;
32- const threads = useGlobalStore ( ( s ) => s . agent . threads ) ;
3321 const currentThreadId = useGlobalStore ( ( s ) => s . agent . currentThreadId ) ;
22+ const rootPath = useGlobalStore ( ( s ) => s . workspace . rootPath ) ;
3423 const workspace = useGlobalStore ( ( s ) => s . workspace ) ;
3524 const setCurrentThread = useGlobalStore ( ( s ) => s . setCurrentThread ) ;
3625 const toggleSidebar = useGlobalStore ( ( s ) => s . toggleSidebar ) ;
3726
38- const projectThreads = getProjectThreads ( threads , workspace . rootPath ) ;
27+ // Subscribe to raw threads, derive list with useMemo for stable reference
28+ const rawThreads = useGlobalStore ( ( s ) => s . agent . threads ) ;
29+ const threadList = useMemo ( ( ) => {
30+ const normalizedRoot = normalizeCwd ( rootPath ) ;
31+ return Object . values ( rawThreads )
32+ . filter ( ( t ) => normalizeCwd ( t . cwd ) . startsWith ( normalizedRoot ) )
33+ . map ( ( t ) => ( { id : t . id , title : t . title , cwd : t . cwd , updatedAt : t . updatedAt } ) )
34+ . sort ( ( a , b ) => b . updatedAt - a . updatedAt ) ;
35+ } , [ rawThreads , rootPath ] ) ;
36+
3937 const [ hoveredThreadId , setHoveredThreadId ] = useState < string | null > ( null ) ;
4038
4139 const handleDelete = async ( threadId : string ) => {
@@ -127,7 +125,7 @@ export default function AgentSidebar() {
127125 会话
128126 </ span >
129127 </ div >
130- { projectThreads . slice ( 0 , 15 ) . map ( ( t ) => (
128+ { threadList . slice ( 0 , 15 ) . map ( ( t ) => (
131129 < button
132130 type = "button"
133131 key = { t . id }
@@ -175,15 +173,15 @@ export default function AgentSidebar() {
175173 ) }
176174 </ button >
177175 ) ) }
178- { projectThreads . length > 15 && (
176+ { threadList . length > 15 && (
179177 < button
180178 type = "button"
181179 className = "w-full text-left px-4 py-1.5 text-[12px] text-[#3a3a3a] hover:text-[#555] transition-colors"
182180 >
183- +{ projectThreads . length - 15 } 条更多
181+ +{ threadList . length - 15 } 条更多
184182 </ button >
185183 ) }
186- { projectThreads . length === 0 && (
184+ { threadList . length === 0 && (
187185 < div className = "px-3 py-4 text-[13px] text-[#3a3a3a]" > 暂无对话</ div >
188186 ) }
189187 </ div >
0 commit comments