Skip to content

Commit b69c949

Browse files
ui tweaks
1 parent 6682dd0 commit b69c949

File tree

5 files changed

+145
-129
lines changed

5 files changed

+145
-129
lines changed

Frontend/src/App/CodeEditor/MonacoEditor/MonacoEditor.tsx

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,25 @@ interface MonacoEditorProps {
1818

1919
export default function MonacoEditor({
2020
selectedFile,
21-
initialValue = "// Select a file to start editing",
21+
initialValue = `
22+
╭─────────────────────────────────────────────╮
23+
│ │
24+
│ Welcome to RTC Code Editor │
25+
│ │
26+
│ Select a file from the sidebar to │
27+
│ start your coding journey │
28+
│ │
29+
│ Features: │
30+
│ • Real-time collaboration │
31+
│ • Syntax highlighting │
32+
│ • Auto-completion │
33+
│ • Multi-language support │
34+
│ • Chat & AI & Much more │
35+
│ │
36+
│ Happy coding! ❤️❤️ │
37+
│ │
38+
╰─────────────────────────────────────────────╯
39+
`,
2240
onFileContentChange,
2341
}: MonacoEditorProps) {
2442
const { theme } = useTheme();
@@ -229,7 +247,7 @@ export default function MonacoEditor({
229247
};
230248

231249
return (
232-
<div className="h-full flex flex-col">
250+
<div className={`h-full flex flex-col ${theme.background}`}>
233251
<CollaborativeCursor
234252
editor={editorRef.current}
235253
selectedFile={
@@ -290,9 +308,9 @@ export default function MonacoEditor({
290308
<div className="flex-1">
291309
<Editor
292310
height="100%"
311+
loading=""
293312
language={language}
294313
theme={theme.monacoTheme}
295-
// Use key to force re-render when file changes
296314
key={selectedFile?.id || "no-file"}
297315
defaultValue={getDisplayContent()}
298316
onMount={handleEditorDidMount}
@@ -320,24 +338,6 @@ export default function MonacoEditor({
320338
}}
321339
/>
322340
</div>
323-
324-
{/* Placeholder when no file is selected */}
325-
{(!selectedFile || selectedFile.type !== "file") && (
326-
<div
327-
className={`absolute inset-0 flex items-center justify-center ${theme.textMuted} pointer-events-none`}
328-
>
329-
<div className="text-center">
330-
<p className="text-lg mb-2">
331-
{!selectedFile ? "No file selected" : "Folder selected"}
332-
</p>
333-
<p className="text-sm">
334-
{!selectedFile
335-
? "Select a file from the explorer to start editing"
336-
: "Select a file (not a folder) to edit its contents"}
337-
</p>
338-
</div>
339-
</div>
340-
)}
341341
</div>
342342
);
343343
}

Frontend/src/App/CodeEditor/ProjectManagementPanel/ProjectManagementPanel.tsx

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,12 +245,28 @@ const ProjectManagementPanel = ({
245245
onCreateFolder={() => handleCreateFolder(null)}
246246
/>
247247

248-
<div
248+
{/* <div
249249
className="flex-1 overflow-y-auto"
250250
onDragOver={(e) => e.preventDefault()}
251251
onDrop={handleRootDrop}
252252
>
253253
{renderFileTree(files)}
254+
</div> */}
255+
<div
256+
className="flex-1 overflow-y-auto"
257+
onDragOver={(e) => e.preventDefault()}
258+
onDrop={handleRootDrop}
259+
>
260+
{files.length === 0 ? (
261+
<div
262+
className={`flex items-center justify-center py-10 p-4 ${theme.textMuted} text-sm`}
263+
>
264+
Give a little time to load
265+
<br /> Or create a new file or folder.
266+
</div>
267+
) : (
268+
renderFileTree(files)
269+
)}
254270
</div>
255271
</div>
256272

Frontend/src/Contexts/EditorContext.tsx

Lines changed: 0 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -281,86 +281,9 @@ export const EditorCollaborationProvider: React.FC<{
281281

282282
// Setup observers
283283
const fileSystemObserver = () => {
284-
// console.log("File system state:", newFileSystemMap.toJSON());
285-
// debuglog();
286284
setFiles(newFileSystemMap.get("files") || []);
287285
};
288286

289-
const debuglog = () => {
290-
// Setup observers
291-
console.log("=== FILE SYSTEM OBSERVER TRIGGERED ===");
292-
console.log("File system state:", newFileSystemMap.toJSON());
293-
294-
// Log all Yjs document values
295-
if (docRef.current) {
296-
console.log("=== ALL YJS DOCUMENT VALUES ===");
297-
298-
// Log all shared types in the document
299-
const sharedTypes = docRef.current.share;
300-
console.log("Shared types keys:", Object.keys(sharedTypes));
301-
302-
// Log fileSystem map
303-
const fileSystemData = newFileSystemMap.toJSON();
304-
console.log("FileSystem Map:", fileSystemData);
305-
306-
// Log chat array
307-
const chatData = newChatArray.toArray();
308-
console.log("Chat Array:", chatData);
309-
310-
// Log all file contents
311-
console.log("=== FILE CONTENTS ===");
312-
const files = newFileSystemMap.get("files") || [];
313-
314-
// Helper function to get all file IDs from nested structure
315-
const getAllFileIds = (fileTree: FileNode[]): string[] => {
316-
const ids: string[] = [];
317-
const traverse = (items: FileNode[]) => {
318-
for (const item of items) {
319-
if (item.type === "file" && item.id) {
320-
ids.push(item.id);
321-
} else if (item.type === "folder" && item.children) {
322-
traverse(item.children);
323-
}
324-
}
325-
};
326-
traverse(fileTree);
327-
return ids;
328-
};
329-
330-
const fileIds = getAllFileIds(files);
331-
console.log("Found file IDs:", fileIds);
332-
333-
fileIds.forEach((fileId) => {
334-
const fileText = docRef.current!.getText(`file-${fileId}`);
335-
const content = fileText.toString();
336-
console.log(
337-
`File ${fileId} content (${content.length} chars):`,
338-
content.substring(0, 200) + (content.length > 200 ? "..." : "")
339-
);
340-
});
341-
342-
// Log all text objects in the document
343-
console.log("=== ALL TEXT OBJECTS ===");
344-
Object.keys(sharedTypes).forEach((key) => {
345-
const sharedType = sharedTypes[key];
346-
if (sharedType instanceof Y.Text) {
347-
const content = sharedType.toString();
348-
console.log(
349-
`Text[${key}] (${content.length} chars):`,
350-
content.substring(0, 100) + (content.length > 100 ? "..." : "")
351-
);
352-
}
353-
});
354-
355-
// Log document state as binary
356-
console.log("=== DOCUMENT STATE ===");
357-
const state = Y.encodeStateAsUpdate(docRef.current);
358-
console.log("Document state size:", state.length, "bytes");
359-
360-
console.log("=== END DOCUMENT VALUES ===");
361-
}
362-
};
363-
364287
const chatObserver = () => {
365288
setMessages(newChatArray.toArray() || []);
366289
};

WS_Server/src/server.js

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ async function handleVersioningNotification(sessionId, command, status) {
3939
if (doc) {
4040
if (command === "ROLLBACK" && status === "SUCCESS") {
4141
try {
42-
console.log(`Reloading files from Supabase for rollback: ${sessionId}`);
42+
yjsPersistence.stopDebounceForRollback(sessionId);
4343

4444
const fileSystemMap = doc.getMap("fileSystem");
4545
const existingFiles = fileSystemMap.get("files") || [];
@@ -60,9 +60,7 @@ async function handleVersioningNotification(sessionId, command, status) {
6060
};
6161

6262
const existingFileIds = getAllFileIds(existingFiles);
63-
console.log(`Existing file IDs:`, existingFileIds);
6463

65-
// Clear everything in a single transaction
6664
doc.transact(() => {
6765
fileSystemMap.clear();
6866

@@ -72,10 +70,7 @@ async function handleVersioningNotification(sessionId, command, status) {
7270
});
7371
}, "rollback-clear");
7472

75-
// Load fresh data from database in a separate transaction
7673
await yjsPersistence.loadFromDatabase(sessionId, doc, true);
77-
78-
console.log(`Successfully reloaded files for session: ${sessionId}`);
7974
} catch (rollbackError) {
8075
console.error(
8176
`Failed to reload files for rollback in session ${sessionId}:`,

WS_Server/src/yjs-persistence.js

Lines changed: 106 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -170,20 +170,35 @@ export class YjsPersistence {
170170

171171
setupUpdateHandler(sessionId, ydoc) {
172172
ydoc.on("update", (update, origin) => {
173-
console.log(`YDoc update in session ${sessionId}, origin: ${origin}`);
174-
// if (origin !== "persistence") {
175-
// this.debouncedSave(sessionId, ydoc);
176-
// }
173+
if (origin !== "persistence") {
174+
this.debouncedSave(sessionId, ydoc);
175+
}
177176
});
178177
}
179178

180-
debouncedSave(sessionId, ydoc) {
181-
// Clear existing timeout
179+
stopDebounceForRollback(sessionId) {
182180
if (this.saveTimeouts.has(sessionId)) {
183181
clearTimeout(this.saveTimeouts.get(sessionId));
182+
this.saveTimeouts.delete(sessionId);
183+
}
184+
if (this.saveTimeouts.has(`rollback-${sessionId}`)) {
185+
clearTimeout(this.saveTimeouts.get(`rollback-${sessionId}`));
186+
this.saveTimeouts.delete(`rollback-${sessionId}`);
184187
}
188+
const rollbackTimeoutId = setTimeout(() => {
189+
this.saveTimeouts.delete(`rollback-${sessionId}`);
190+
}, this.SAVE_DELAY * 2);
185191

186-
// Set new timeout
192+
this.saveTimeouts.set(`rollback-${sessionId}`, rollbackTimeoutId);
193+
}
194+
195+
debouncedSave(sessionId, ydoc) {
196+
if (this.saveTimeouts.has(`rollback-${sessionId}`)) {
197+
return;
198+
}
199+
if (this.saveTimeouts.has(sessionId)) {
200+
clearTimeout(this.saveTimeouts.get(sessionId));
201+
}
187202
const timeoutId = setTimeout(async () => {
188203
await this.syncToDatabase(sessionId, ydoc);
189204
}, this.SAVE_DELAY);
@@ -231,7 +246,6 @@ export class YjsPersistence {
231246
};
232247

233248
const allFiles = getAllFiles(files);
234-
console.log(`Syncing ${allFiles.length} files for session ${sessionId}`);
235249

236250
const currentFileIds = new Set(
237251
allFiles.map((file) => file.id).filter(Boolean)
@@ -324,26 +338,94 @@ export class YjsPersistence {
324338
}
325339
}
326340

327-
for (const upload of storageUploads) {
328-
const { error: storageError } = await supabase.storage
329-
.from("sessionFiles")
330-
.upload(upload.path, upload.content, {
331-
upsert: true,
332-
contentType: "text/plain",
341+
if (storageUploads.length > 0) {
342+
const BATCH_SIZE = 10; // Upload 10 files at once
343+
const batches = [];
344+
345+
for (let i = 0; i < storageUploads.length; i += BATCH_SIZE) {
346+
batches.push(storageUploads.slice(i, i + BATCH_SIZE));
347+
}
348+
349+
for (const [batchIndex, batch] of batches.entries()) {
350+
const uploadPromises = batch.map(async (upload) => {
351+
try {
352+
const { error: storageError } = await supabase.storage
353+
.from("sessionFiles")
354+
.upload(upload.path, upload.content, {
355+
upsert: true,
356+
contentType: "text/plain",
357+
});
358+
359+
if (
360+
storageError &&
361+
storageError.message !== "The resource already exists"
362+
) {
363+
console.error(
364+
`Error uploading file to storage (${upload.path}):`,
365+
storageError
366+
);
367+
return {
368+
success: false,
369+
path: upload.path,
370+
error: storageError,
371+
};
372+
}
373+
374+
return { success: true, path: upload.path };
375+
} catch (error) {
376+
console.error(
377+
`Exception uploading file (${upload.path}):`,
378+
error
379+
);
380+
return { success: false, path: upload.path, error };
381+
}
333382
});
334383

335-
if (storageError) {
336-
// Ignore "The resource already exists" error if upsert is true
337-
if (storageError.message !== "The resource already exists") {
338-
console.error(
339-
`Error uploading file to storage (${upload.path}):`,
340-
storageError
341-
);
342-
}
343-
} else {
344-
console.log(`✅ Uploaded file to storage: ${upload.path}`);
384+
const results = await Promise.allSettled(uploadPromises);
385+
386+
const successful = results.filter(
387+
(r) => r.status === "fulfilled" && r.value.success
388+
).length;
389+
const failed = results.filter(
390+
(r) =>
391+
r.status === "rejected" ||
392+
(r.status === "fulfilled" && !r.value.success)
393+
).length;
394+
395+
console.log(
396+
`Batch ${
397+
batchIndex + 1
398+
} complete: ${successful} successful, ${failed} failed`
399+
);
400+
401+
results.forEach((result) => {
402+
if (result.status === "fulfilled" && result.value.success) {
403+
console.log(`✅ Uploaded file to storage: ${result.value.path}`);
404+
}
405+
});
345406
}
346407
}
408+
409+
// for (const upload of storageUploads) {
410+
// const { error: storageError } = await supabase.storage
411+
// .from("sessionFiles")
412+
// .upload(upload.path, upload.content, {
413+
// upsert: true,
414+
// contentType: "text/plain",
415+
// });
416+
417+
// if (storageError) {
418+
// // Ignore "The resource already exists" error if upsert is true
419+
// if (storageError.message !== "The resource already exists") {
420+
// console.error(
421+
// `Error uploading file to storage (${upload.path}):`,
422+
// storageError
423+
// );
424+
// }
425+
// } else {
426+
// console.log(`✅ Uploaded file to storage: ${upload.path}`);
427+
// }
428+
// }
347429
} catch (error) {
348430
console.error(
349431
`Failed to sync to database for session ${sessionId}:`,

0 commit comments

Comments
 (0)