Skip to content

Commit 58d7553

Browse files
author
pengyu
committed
finish caching problem and half way through the project
1 parent 1486346 commit 58d7553

11 files changed

Lines changed: 206 additions & 181 deletions

File tree

backend/src/project/project.service.ts

Lines changed: 27 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -198,27 +198,37 @@ export class ProjectService {
198198
this.logger.debug(`Generated project name: ${projectName}`);
199199
}
200200

201+
// Create project entity with "(Generating...)" suffix
202+
const project = new Project();
203+
project.projectName = `${projectName} (Generating...)`;
204+
project.projectPath = ''; // Will be updated when actual project is generated
205+
project.userId = userId;
206+
project.isPublic = input.public || false;
207+
project.uniqueProjectId = uuidv4();
208+
project.projectPackages = [];
209+
210+
// Save project
211+
const savedProject = await this.projectsRepository.save(project);
212+
201213
// Create chat with proper title
202214
const defaultChat = await this.chatService.createChatWithMessage(userId, {
203215
title: projectName || 'New Project Chat',
204216
message: input.description,
205217
});
206218

207-
// Perform the rest of project creation asynchronously
208-
this.createProjectInBackground(input, projectName, userId, defaultChat);
219+
// Bind chat to project
220+
await this.bindProjectAndChat(savedProject, defaultChat);
221+
222+
// Perform project creation asynchronously
223+
this.createProjectInBackground(input, projectName, userId, defaultChat, savedProject);
209224

210225
// Return chat immediately so user can start interacting
211226
return defaultChat;
212227
} catch (error) {
213-
if (error instanceof ProjectRateLimitException) {
214-
throw error.getGraphQLError(); // Throw as a GraphQL error for the client
215-
}
216-
217-
this.logger.error(
218-
`Error in createProject: ${error.message}`,
219-
error.stack,
228+
this.logger.error(`Error creating project: ${error.message}`, error.stack);
229+
throw new InternalServerErrorException(
230+
`Failed to create project: ${error.message}`,
220231
);
221-
throw new InternalServerErrorException('Error creating the project.');
222232
}
223233
}
224234

@@ -228,6 +238,7 @@ export class ProjectService {
228238
projectName: string,
229239
userId: string,
230240
chat: Chat,
241+
project: Project,
231242
): Promise<void> {
232243
try {
233244
// Build project sequence and execute
@@ -238,13 +249,9 @@ export class ProjectService {
238249
const context = new BuilderContext(sequence, sequence.id);
239250
const projectPath = await context.execute();
240251

241-
// Create project entity and set properties
242-
const project = new Project();
243-
project.projectName = projectName;
252+
// Update project with actual data
253+
project.projectName = projectName; // Remove "(Generating...)" suffix
244254
project.projectPath = projectPath;
245-
project.userId = userId;
246-
project.isPublic = input.public || false;
247-
project.uniqueProjectId = uuidv4();
248255

249256
// Set project packages
250257
try {
@@ -253,25 +260,13 @@ export class ProjectService {
253260
);
254261
} catch (packageError) {
255262
this.logger.error(`Error processing packages: ${packageError.message}`);
256-
// Continue even if packages processing fails
257263
project.projectPackages = [];
258264
}
259265

260-
// Save project
266+
// Save updated project
261267
const savedProject = await this.projectsRepository.save(project);
262-
this.logger.debug(`Project created: ${savedProject.id}`);
268+
this.logger.debug(`Project updated: ${savedProject.id}`);
263269

264-
// Bind chat to project
265-
const bindSuccess = await this.bindProjectAndChat(savedProject, chat);
266-
if (!bindSuccess) {
267-
this.logger.error(
268-
`Failed to bind project and chat: ${savedProject.id} -> ${chat.id}`,
269-
);
270-
} else {
271-
this.logger.debug(
272-
`Project and chat bound: ${savedProject.id} -> ${chat.id}`,
273-
);
274-
}
275270
} catch (error) {
276271
this.logger.error(
277272
`Error in background project creation: ${error.message}`,
@@ -808,7 +803,7 @@ export class ProjectService {
808803
this.logger.log(
809804
'check if the github project exist: ' + project.isSyncedWithGitHub,
810805
);
811-
// 2) Check users GitHub installation
806+
// 2) Check user's GitHub installation
812807
if (!user.githubInstallationId) {
813808
throw new Error('GitHub App not installed for this user');
814809
}
@@ -819,7 +814,7 @@ export class ProjectService {
819814
);
820815
const userOAuthToken = user.githubAccessToken;
821816

822-
// 4) Create the repo if the project doesnt have it yet
817+
// 4) Create the repo if the project doesn't have it yet
823818
if (!project.githubRepoName || !project.githubOwner) {
824819
// Use project.projectName or generate a safe name
825820

frontend/src/components/chat/code-engine/code-engine.tsx

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import ConsoleTab from './tabs/console-tab';
1010
import ResponsiveToolbar from './responsive-toolbar';
1111
import SaveChangesBar from './save-changes-bar';
1212
import { logger } from '@/app/log/logger';
13+
import { useAuthContext } from '@/providers/AuthProvider';
1314

1415
export function CodeEngine({
1516
chatId,
@@ -27,6 +28,7 @@ export function CodeEngine({
2728
editorRef,
2829
setRecentlyCompletedProjectId,
2930
} = useContext(ProjectContext);
31+
const { user } = useAuthContext();
3032
const [localProject, setLocalProject] = useState(null);
3133
const [isLoading, setIsLoading] = useState(true);
3234
const [filePath, setFilePath] = useState<string | null>(null);
@@ -330,7 +332,7 @@ export function CodeEngine({
330332
setProjectCompleted(true);
331333
isProjectLoadedRef.current = true;
332334
try {
333-
localStorage.setItem(`project-completed-${chatId}`, 'true');
335+
localStorage.setItem(getUserStorageKey(`project-completed-${chatId}`), 'true');
334336
} catch (e) {
335337
logger.error('Failed to save project completion status:', e);
336338
}
@@ -369,6 +371,32 @@ export function CodeEngine({
369371
return () => interval && clearInterval(interval);
370372
}, [timerActive]);
371373

374+
// 获取带用户ID的localStorage键
375+
const getUserStorageKey = (key: string) => {
376+
return user?.id ? `${key}_${user.id}` : key;
377+
};
378+
379+
useEffect(() => {
380+
if (
381+
curProject?.projectPath &&
382+
chatId &&
383+
projectCompleted &&
384+
!isProjectLoadedRef.current
385+
) {
386+
setProgress(100);
387+
setTimerActive(false);
388+
setIsCompleting(false);
389+
setProjectCompleted(true);
390+
isProjectLoadedRef.current = true;
391+
392+
try {
393+
localStorage.setItem(getUserStorageKey(`project-completed-${chatId}`), 'true');
394+
} catch (e) {
395+
logger.error('Failed to save project completion status:', e);
396+
}
397+
}
398+
}, [curProject?.projectPath, chatId, projectCompleted, user?.id]);
399+
372400
return (
373401
<div className="rounded-lg border shadow-sm overflow-scroll h-full">
374402
<ResponsiveToolbar

frontend/src/components/chat/code-engine/project-context.tsx

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -117,10 +117,16 @@ export function ProjectProvider({ children }: { children: ReactNode }) {
117117
const [filePath, setFilePath] = useState<string | null>(null);
118118
const [isLoading, setIsLoading] = useState<boolean>(false);
119119
const editorRef = useRef<any>(null);
120+
121+
// 获取带用户ID的localStorage键
122+
const getUserStorageKey = (key: string) => {
123+
return user?.id ? `${key}_${user.id}` : key;
124+
};
125+
120126
const [pendingProjects, setPendingProjects] = useState<Project[]>(() => {
121-
if (typeof window !== 'undefined') {
127+
if (typeof window !== 'undefined' && user?.id) {
122128
try {
123-
const raw = localStorage.getItem('pendingProjects');
129+
const raw = localStorage.getItem(getUserStorageKey('pendingProjects'));
124130
if (raw) {
125131
return JSON.parse(raw) as Project[];
126132
}
@@ -130,50 +136,54 @@ export function ProjectProvider({ children }: { children: ReactNode }) {
130136
}
131137
return [];
132138
});
139+
133140
const setRecentlyCompletedProjectId = (id: string | null) => {
134-
if (typeof window !== 'undefined') {
141+
if (typeof window !== 'undefined' && user?.id) {
135142
if (id) {
136-
localStorage.setItem('pendingChatId', id);
143+
localStorage.setItem(getUserStorageKey('pendingChatId'), id);
137144
} else {
138-
localStorage.removeItem('pendingChatId');
145+
localStorage.removeItem(getUserStorageKey('pendingChatId'));
139146
}
140147
}
141148
setRecentlyCompletedProjectIdRaw(id);
142149
};
143150

144151
const [recentlyCompletedProjectIdRaw, setRecentlyCompletedProjectIdRaw] =
145152
useState<string | null>(() =>
146-
typeof window !== 'undefined'
147-
? localStorage.getItem('pendingChatId')
153+
typeof window !== 'undefined' && user?.id
154+
? localStorage.getItem(getUserStorageKey('pendingChatId'))
148155
: null
149156
);
157+
150158
useEffect(() => {
151-
if (typeof window === 'undefined') return;
159+
if (typeof window === 'undefined' || !user?.id) return;
152160
try {
153-
localStorage.setItem('pendingProjects', JSON.stringify(pendingProjects));
161+
localStorage.setItem(getUserStorageKey('pendingProjects'), JSON.stringify(pendingProjects));
154162
} catch (e) {
155163
logger.warn('Failed to store pendingProjects in localStorage');
156164
}
157-
}, [pendingProjects]);
165+
}, [pendingProjects, user?.id]);
166+
158167
// setter:更新 state + localStorage
159168
const setTempLoadingProjectId = (id: string | null) => {
160-
if (typeof window !== 'undefined') {
169+
if (typeof window !== 'undefined' && user?.id) {
161170
if (id) {
162-
localStorage.setItem('tempLoadingProjectId', id);
171+
localStorage.setItem(getUserStorageKey('tempLoadingProjectId'), id);
163172
} else {
164-
localStorage.removeItem('tempLoadingProjectId');
173+
localStorage.removeItem(getUserStorageKey('tempLoadingProjectId'));
165174
}
166175
}
167176
setTempLoadingProjectIdRaw(id);
168177
};
178+
169179
const [chatId, setChatId] = useState<string | null>(null);
170180
const [pollTime, setPollTime] = useState(Date.now());
171181
const [isCreateButtonClicked, setIsCreateButtonClicked] = useState(false);
172182
const [tempLoadingProjectIdRaw, setTempLoadingProjectIdRaw] = useState<
173183
string | null
174184
>(() => {
175-
if (typeof window !== 'undefined') {
176-
return localStorage.getItem('tempLoadingProjectId');
185+
if (typeof window !== 'undefined' && user?.id) {
186+
return localStorage.getItem(getUserStorageKey('tempLoadingProjectId'));
177187
}
178188
return null;
179189
});
@@ -795,7 +805,7 @@ export function ProjectProvider({ children }: { children: ReactNode }) {
795805
if (createdChat?.id) {
796806
setChatId(createdChat.id);
797807
setIsCreateButtonClicked(true);
798-
localStorage.setItem('pendingChatId', createdChat.id);
808+
localStorage.setItem(getUserStorageKey('pendingChatId'), createdChat.id);
799809
setTempLoadingProjectId(createdChat.id);
800810
return createdChat.id;
801811
} else {

frontend/src/components/chat/project-modal.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ export interface Project {
55
id: string;
66
projectName: string;
77
projectPath: string;
8-
createdAt: number;
9-
updatedAt: number;
8+
createdAt: string;
9+
updatedAt: string;
1010
isActive: boolean;
1111
isDeleted: boolean;
1212
userId: string;

frontend/src/components/global-toast-listener.tsx

Lines changed: 0 additions & 96 deletions
This file was deleted.

frontend/src/components/root/expand-card.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ export function ExpandableCard({ projects, isGenerating = false, onOpenChat }) {
201201
onOpenChat();
202202
}}
203203
>
204-
Open Chat
204+
{/* Open Chat */}
205205
</Button>
206206
</div>
207207
)}

0 commit comments

Comments
 (0)