codev / desktop /src /stores /memoryStore.ts
chenbhao's picture
feat: desktop
1f21206
Raw
History Blame
4.16 kB
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<void>
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
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)
} catch (err) {
set({ error: (err as Error).message, isSaving: 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 })
}
},
}))