fix: improve shutdown and project continuity
This commit is contained in:
@@ -1723,6 +1723,58 @@ describe('App', () => {
|
||||
)
|
||||
})
|
||||
|
||||
it('restores and persists the last active project', async () => {
|
||||
const secondProject = {
|
||||
...project,
|
||||
id: '00000000-0000-4000-8000-000000000102',
|
||||
name: '第二项目',
|
||||
rootPath: 'C:\\Second',
|
||||
defaultWorkMode: 'execute' as const
|
||||
}
|
||||
vi.mocked(api.projects.list).mockResolvedValueOnce([
|
||||
project,
|
||||
secondProject
|
||||
])
|
||||
localStorage.setItem(
|
||||
'goodbuddy.active-project.v1',
|
||||
secondProject.id
|
||||
)
|
||||
|
||||
render(<App />)
|
||||
|
||||
expect(await screen.findByLabelText('当前项目')).toHaveValue(
|
||||
secondProject.id
|
||||
)
|
||||
expect(screen.getByLabelText('工作模式')).toHaveValue('execute')
|
||||
|
||||
fireEvent.change(screen.getByLabelText('当前项目'), {
|
||||
target: { value: project.id }
|
||||
})
|
||||
await waitFor(() =>
|
||||
expect(
|
||||
localStorage.getItem('goodbuddy.active-project.v1')
|
||||
).toBe(project.id)
|
||||
)
|
||||
})
|
||||
|
||||
it('falls back when the last active project is no longer available', async () => {
|
||||
localStorage.setItem(
|
||||
'goodbuddy.active-project.v1',
|
||||
'00000000-0000-4000-8000-000000000999'
|
||||
)
|
||||
|
||||
render(<App />)
|
||||
|
||||
expect(await screen.findByLabelText('当前项目')).toHaveValue(
|
||||
project.id
|
||||
)
|
||||
await waitFor(() =>
|
||||
expect(
|
||||
localStorage.getItem('goodbuddy.active-project.v1')
|
||||
).toBe(project.id)
|
||||
)
|
||||
})
|
||||
|
||||
it.each([
|
||||
['opencode', 'OpenCode'],
|
||||
['continue', 'Continue CLI']
|
||||
|
||||
@@ -352,6 +352,8 @@ const emptyTokenUsage: TokenUsageSummary = {
|
||||
|
||||
const storageKey = 'goodbuddy.conversations.v1'
|
||||
|
||||
const activeProjectStorageKey = 'goodbuddy.active-project.v1'
|
||||
|
||||
const quickActions = [
|
||||
{
|
||||
title: '总结一段内容',
|
||||
@@ -644,6 +646,14 @@ function loadConversations(): Conversation[] {
|
||||
}
|
||||
}
|
||||
|
||||
function loadActiveProjectId(): string | undefined {
|
||||
try {
|
||||
return localStorage.getItem(activeProjectStorageKey) || undefined
|
||||
} catch {
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
|
||||
function isConversation(value: unknown): value is Conversation {
|
||||
if (!value || typeof value !== 'object') {
|
||||
return false
|
||||
@@ -2200,6 +2210,13 @@ function App(): React.JSX.Element {
|
||||
|
||||
useEffect(() => {
|
||||
activeProjectIdRef.current = activeProjectId
|
||||
if (activeProjectId) {
|
||||
try {
|
||||
localStorage.setItem(activeProjectStorageKey, activeProjectId)
|
||||
} catch {
|
||||
// The project selection still works when persistence is unavailable.
|
||||
}
|
||||
}
|
||||
}, [activeProjectId])
|
||||
|
||||
useEffect(() => {
|
||||
@@ -2238,7 +2255,11 @@ function App(): React.JSX.Element {
|
||||
if (!active || value.length === 0) {
|
||||
return
|
||||
}
|
||||
const project = value[0]!
|
||||
const lastActiveProjectId = loadActiveProjectId()
|
||||
const project =
|
||||
value.find(
|
||||
(candidate) => candidate.id === lastActiveProjectId
|
||||
) ?? value[0]!
|
||||
setProjects(value)
|
||||
setActiveProjectId(project.id)
|
||||
setWorkMode(
|
||||
|
||||
Reference in New Issue
Block a user