mirror of
https://github.com/NanmiCoder/cc-haha
synced 2026-07-16 13:03:31 +08:00
Tested: cd desktop && bun run test src/__tests__/memorySettings.test.tsx Tested: bun run check:desktop Scope-risk: narrow Confidence: high
141 lines
4.1 KiB
TypeScript
141 lines
4.1 KiB
TypeScript
import { create } from 'zustand'
|
|
import { memoryApi } from '../api/memory'
|
|
import type { MemoryFile, MemoryFileDetail, MemoryProject } from '../types/memory'
|
|
|
|
type MemoryStore = {
|
|
projects: MemoryProject[]
|
|
files: MemoryFile[]
|
|
selectedProjectId: string | null
|
|
selectedFile: MemoryFileDetail | null
|
|
draftContent: string
|
|
isLoadingProjects: boolean
|
|
isLoadingFiles: boolean
|
|
isLoadingFile: boolean
|
|
isSaving: boolean
|
|
error: string | null
|
|
lastSavedAt: string | null
|
|
|
|
fetchProjects: (cwd?: string) => Promise<void>
|
|
selectProject: (projectId: string) => void
|
|
fetchFiles: (projectId: string) => Promise<void>
|
|
openFile: (projectId: string, path: string) => Promise<void>
|
|
updateDraft: (content: string) => void
|
|
saveFile: () => Promise<boolean>
|
|
createFile: (projectId: string, path: string, content: string) => Promise<void>
|
|
}
|
|
|
|
export const useMemoryStore = create<MemoryStore>((set, get) => ({
|
|
projects: [],
|
|
files: [],
|
|
selectedProjectId: null,
|
|
selectedFile: null,
|
|
draftContent: '',
|
|
isLoadingProjects: false,
|
|
isLoadingFiles: false,
|
|
isLoadingFile: false,
|
|
isSaving: false,
|
|
error: null,
|
|
lastSavedAt: null,
|
|
|
|
fetchProjects: async (cwd) => {
|
|
set({ isLoadingProjects: true, error: null })
|
|
try {
|
|
const { projects } = await memoryApi.listProjects(cwd)
|
|
const current = projects.find((project) => project.isCurrent)
|
|
const selectedProjectId =
|
|
get().selectedProjectId && projects.some((project) => project.id === get().selectedProjectId)
|
|
? get().selectedProjectId
|
|
: current?.id ?? projects[0]?.id ?? null
|
|
set({ projects, selectedProjectId, isLoadingProjects: false })
|
|
} catch (err) {
|
|
set({ error: (err as Error).message, isLoadingProjects: false })
|
|
}
|
|
},
|
|
|
|
selectProject: (projectId) => {
|
|
set({
|
|
selectedProjectId: projectId,
|
|
files: [],
|
|
selectedFile: null,
|
|
draftContent: '',
|
|
error: null,
|
|
lastSavedAt: null,
|
|
})
|
|
},
|
|
|
|
fetchFiles: async (projectId) => {
|
|
set({ isLoadingFiles: true, error: null })
|
|
try {
|
|
const { files } = await memoryApi.listFiles(projectId)
|
|
set((state) => {
|
|
const stillSelected = state.selectedFile && files.some((file) => file.path === state.selectedFile?.path)
|
|
return {
|
|
files,
|
|
selectedFile: stillSelected ? state.selectedFile : null,
|
|
draftContent: stillSelected ? state.draftContent : '',
|
|
isLoadingFiles: false,
|
|
}
|
|
})
|
|
} catch (err) {
|
|
set({ error: (err as Error).message, isLoadingFiles: false })
|
|
}
|
|
},
|
|
|
|
openFile: async (projectId, path) => {
|
|
set({ isLoadingFile: true, error: null })
|
|
try {
|
|
const { file } = await memoryApi.readFile(projectId, path)
|
|
set({
|
|
selectedFile: file,
|
|
draftContent: file.content,
|
|
isLoadingFile: false,
|
|
lastSavedAt: null,
|
|
})
|
|
} catch (err) {
|
|
set({ error: (err as Error).message, isLoadingFile: false })
|
|
}
|
|
},
|
|
|
|
updateDraft: (content) => set({ draftContent: content }),
|
|
|
|
saveFile: async () => {
|
|
const { selectedProjectId, selectedFile, draftContent } = get()
|
|
if (!selectedProjectId || !selectedFile) return false
|
|
set({ isSaving: true, error: null })
|
|
try {
|
|
const { file } = await memoryApi.saveFile({
|
|
projectId: selectedProjectId,
|
|
path: selectedFile.path,
|
|
content: draftContent,
|
|
})
|
|
set({
|
|
selectedFile: {
|
|
...selectedFile,
|
|
updatedAt: file.updatedAt,
|
|
bytes: file.bytes,
|
|
content: draftContent,
|
|
},
|
|
isSaving: false,
|
|
lastSavedAt: file.updatedAt,
|
|
})
|
|
await get().fetchFiles(selectedProjectId)
|
|
return true
|
|
} catch (err) {
|
|
set({ error: (err as Error).message, isSaving: false })
|
|
return false
|
|
}
|
|
},
|
|
|
|
createFile: async (projectId, path, content) => {
|
|
set({ isSaving: true, error: null })
|
|
try {
|
|
await memoryApi.saveFile({ projectId, path, content })
|
|
set({ isSaving: false })
|
|
await get().fetchFiles(projectId)
|
|
await get().openFile(projectId, path)
|
|
} catch (err) {
|
|
set({ error: (err as Error).message, isSaving: false })
|
|
}
|
|
},
|
|
}))
|