From bd33eb9b1c56775247a1fe4065b12acedbfb764a Mon Sep 17 00:00:00 2001 From: Akhilesh Rangani Date: Fri, 14 Jun 2024 16:56:47 +0000 Subject: [PATCH] update --- .../database/drizzle/meta/0000_snapshot.json | 349 ++++++++++-------- .../database/drizzle/meta/0001_snapshot.json | 175 --------- .../database/drizzle/meta/0002_snapshot.json | 168 --------- .../database/drizzle/meta/0003_snapshot.json | 175 --------- backend/database/drizzle/meta/_journal.json | 66 +--- frontend/components/editor/index.tsx | 153 ++++---- frontend/lib/utils.ts | 10 + 7 files changed, 300 insertions(+), 796 deletions(-) delete mode 100644 backend/database/drizzle/meta/0001_snapshot.json delete mode 100644 backend/database/drizzle/meta/0002_snapshot.json delete mode 100644 backend/database/drizzle/meta/0003_snapshot.json diff --git a/backend/database/drizzle/meta/0000_snapshot.json b/backend/database/drizzle/meta/0000_snapshot.json index aadfc3e..5f81b24 100644 --- a/backend/database/drizzle/meta/0000_snapshot.json +++ b/backend/database/drizzle/meta/0000_snapshot.json @@ -1,168 +1,197 @@ { - "version": "5", - "dialect": "sqlite", - "id": "6570ba20-a672-400c-8147-7ba533784918", - "prevId": "00000000-0000-0000-0000-000000000000", - "tables": { - "sandbox": { - "name": "sandbox", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true, - "autoincrement": false + "version": "5", + "dialect": "sqlite", + "id": "70e3d022-aed8-4464-9063-c92113b4ebe2", + "prevId": "00000000-0000-0000-0000-000000000000", + "tables": { + "sandbox": { + "name": "sandbox", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "visibility": { + "name": "visibility", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "createdAt": { + "name": "createdAt", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false + "indexes": { + "sandbox_id_unique": { + "name": "sandbox_id_unique", + "columns": [ + "id" + ], + "isUnique": true + } }, - "type": { - "name": "type", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false + "foreignKeys": { + "sandbox_user_id_user_id_fk": { + "name": "sandbox_user_id_user_id_fk", + "tableFrom": "sandbox", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } }, - "visibility": { - "name": "visibility", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } + "compositePrimaryKeys": {}, + "uniqueConstraints": {} }, - "indexes": { - "sandbox_id_unique": { - "name": "sandbox_id_unique", - "columns": [ - "id" - ], - "isUnique": true - } + "user": { + "name": "user", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "generations": { + "name": "generations", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": 0 + } + }, + "indexes": { + "user_id_unique": { + "name": "user_id_unique", + "columns": [ + "id" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} }, - "foreignKeys": { - "sandbox_user_id_user_id_fk": { - "name": "sandbox_user_id_user_id_fk", - "tableFrom": "sandbox", - "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "users_to_sandboxes": { + "name": "users_to_sandboxes", + "columns": { + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "sandboxId": { + "name": "sandboxId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "sharedOn": { + "name": "sharedOn", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "users_to_sandboxes_userId_user_id_fk": { + "name": "users_to_sandboxes_userId_user_id_fk", + "tableFrom": "users_to_sandboxes", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "users_to_sandboxes_sandboxId_sandbox_id_fk": { + "name": "users_to_sandboxes_sandboxId_sandbox_id_fk", + "tableFrom": "users_to_sandboxes", + "tableTo": "sandbox", + "columnsFrom": [ + "sandboxId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + } }, - "user": { - "name": "user", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "user_id_unique": { - "name": "user_id_unique", - "columns": [ - "id" - ], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {} - }, - "users_to_sandboxes": { - "name": "users_to_sandboxes", - "columns": { - "userId": { - "name": "userId", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "sandboxId": { - "name": "sandboxId", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": { - "users_to_sandboxes_userId_user_id_fk": { - "name": "users_to_sandboxes_userId_user_id_fk", - "tableFrom": "users_to_sandboxes", - "tableTo": "user", - "columnsFrom": [ - "userId" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "users_to_sandboxes_sandboxId_sandbox_id_fk": { - "name": "users_to_sandboxes_sandboxId_sandbox_id_fk", - "tableFrom": "users_to_sandboxes", - "tableTo": "sandbox", - "columnsFrom": [ - "sandboxId" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {} + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} } - }, - "enums": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": {} - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/backend/database/drizzle/meta/0001_snapshot.json b/backend/database/drizzle/meta/0001_snapshot.json deleted file mode 100644 index bc042fe..0000000 --- a/backend/database/drizzle/meta/0001_snapshot.json +++ /dev/null @@ -1,175 +0,0 @@ -{ - "version": "5", - "dialect": "sqlite", - "id": "9f64104a-4954-40c0-8155-17755ea0a243", - "prevId": "6570ba20-a672-400c-8147-7ba533784918", - "tables": { - "sandbox": { - "name": "sandbox", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "type": { - "name": "type", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "visibility": { - "name": "visibility", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "sandbox_id_unique": { - "name": "sandbox_id_unique", - "columns": [ - "id" - ], - "isUnique": true - } - }, - "foreignKeys": { - "sandbox_user_id_user_id_fk": { - "name": "sandbox_user_id_user_id_fk", - "tableFrom": "sandbox", - "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {} - }, - "user": { - "name": "user", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "image": { - "name": "image", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "user_id_unique": { - "name": "user_id_unique", - "columns": [ - "id" - ], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {} - }, - "users_to_sandboxes": { - "name": "users_to_sandboxes", - "columns": { - "userId": { - "name": "userId", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "sandboxId": { - "name": "sandboxId", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": { - "users_to_sandboxes_userId_user_id_fk": { - "name": "users_to_sandboxes_userId_user_id_fk", - "tableFrom": "users_to_sandboxes", - "tableTo": "user", - "columnsFrom": [ - "userId" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "users_to_sandboxes_sandboxId_sandbox_id_fk": { - "name": "users_to_sandboxes_sandboxId_sandbox_id_fk", - "tableFrom": "users_to_sandboxes", - "tableTo": "sandbox", - "columnsFrom": [ - "sandboxId" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {} - } - }, - "enums": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": {} - } -} \ No newline at end of file diff --git a/backend/database/drizzle/meta/0002_snapshot.json b/backend/database/drizzle/meta/0002_snapshot.json deleted file mode 100644 index 2156a39..0000000 --- a/backend/database/drizzle/meta/0002_snapshot.json +++ /dev/null @@ -1,168 +0,0 @@ -{ - "version": "5", - "dialect": "sqlite", - "id": "5baf10d6-7697-42ba-a11a-ee4c7bd7e91e", - "prevId": "9f64104a-4954-40c0-8155-17755ea0a243", - "tables": { - "sandbox": { - "name": "sandbox", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "type": { - "name": "type", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "visibility": { - "name": "visibility", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "sandbox_id_unique": { - "name": "sandbox_id_unique", - "columns": [ - "id" - ], - "isUnique": true - } - }, - "foreignKeys": { - "sandbox_user_id_user_id_fk": { - "name": "sandbox_user_id_user_id_fk", - "tableFrom": "sandbox", - "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {} - }, - "user": { - "name": "user", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "user_id_unique": { - "name": "user_id_unique", - "columns": [ - "id" - ], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {} - }, - "users_to_sandboxes": { - "name": "users_to_sandboxes", - "columns": { - "userId": { - "name": "userId", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "sandboxId": { - "name": "sandboxId", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": { - "users_to_sandboxes_userId_user_id_fk": { - "name": "users_to_sandboxes_userId_user_id_fk", - "tableFrom": "users_to_sandboxes", - "tableTo": "user", - "columnsFrom": [ - "userId" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "users_to_sandboxes_sandboxId_sandbox_id_fk": { - "name": "users_to_sandboxes_sandboxId_sandbox_id_fk", - "tableFrom": "users_to_sandboxes", - "tableTo": "sandbox", - "columnsFrom": [ - "sandboxId" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {} - } - }, - "enums": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": {} - } -} \ No newline at end of file diff --git a/backend/database/drizzle/meta/0003_snapshot.json b/backend/database/drizzle/meta/0003_snapshot.json deleted file mode 100644 index 086eefe..0000000 --- a/backend/database/drizzle/meta/0003_snapshot.json +++ /dev/null @@ -1,175 +0,0 @@ -{ - "version": "5", - "dialect": "sqlite", - "id": "37e38b82-1494-4818-8c26-b9024cce3fa9", - "prevId": "5baf10d6-7697-42ba-a11a-ee4c7bd7e91e", - "tables": { - "sandbox": { - "name": "sandbox", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "type": { - "name": "type", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "visibility": { - "name": "visibility", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "sandbox_id_unique": { - "name": "sandbox_id_unique", - "columns": [ - "id" - ], - "isUnique": true - } - }, - "foreignKeys": { - "sandbox_user_id_user_id_fk": { - "name": "sandbox_user_id_user_id_fk", - "tableFrom": "sandbox", - "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {} - }, - "user": { - "name": "user", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "image": { - "name": "image", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "user_id_unique": { - "name": "user_id_unique", - "columns": [ - "id" - ], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {} - }, - "users_to_sandboxes": { - "name": "users_to_sandboxes", - "columns": { - "userId": { - "name": "userId", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "sandboxId": { - "name": "sandboxId", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": { - "users_to_sandboxes_userId_user_id_fk": { - "name": "users_to_sandboxes_userId_user_id_fk", - "tableFrom": "users_to_sandboxes", - "tableTo": "user", - "columnsFrom": [ - "userId" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "users_to_sandboxes_sandboxId_sandbox_id_fk": { - "name": "users_to_sandboxes_sandboxId_sandbox_id_fk", - "tableFrom": "users_to_sandboxes", - "tableTo": "sandbox", - "columnsFrom": [ - "sandboxId" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {} - } - }, - "enums": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": {} - } -} \ No newline at end of file diff --git a/backend/database/drizzle/meta/_journal.json b/backend/database/drizzle/meta/_journal.json index 352aca6..835b81c 100644 --- a/backend/database/drizzle/meta/_journal.json +++ b/backend/database/drizzle/meta/_journal.json @@ -1,55 +1,13 @@ { - "version": "5", - "dialect": "sqlite", - "entries": [ - { - "idx": 0, - "version": "5", - "when": 1714540200800, - "tag": "0000_big_rogue", - "breakpoints": true - }, - { - "idx": 1, - "version": "5", - "when": 1714541190588, - "tag": "0001_empty_black_knight", - "breakpoints": true - }, - { - "idx": 2, - "version": "5", - "when": 1714541209173, - "tag": "0002_sour_ego", - "breakpoints": true - }, - { - "idx": 3, - "version": "5", - "when": 1714541233589, - "tag": "0003_pale_overlord", - "breakpoints": true - }, - { - "idx": 4, - "version": "5", - "when": 1714565073180, - "tag": "0004_cuddly_wolf_cub", - "breakpoints": true - }, - { - "idx": 5, - "version": "5", - "when": 1714950365718, - "tag": "0005_last_the_twelve", - "breakpoints": true - }, - { - "idx": 6, - "version": "5", - "when": 1716432225404, - "tag": "0006_lively_mattie_franklin", - "breakpoints": true - } - ] -} \ No newline at end of file + "version": "5", + "dialect": "sqlite", + "entries": [ + { + "idx": 0, + "version": "5", + "when": 1718032216030, + "tag": "0000_melodic_the_captain", + "breakpoints": true + } + ] + } \ No newline at end of file diff --git a/frontend/components/editor/index.tsx b/frontend/components/editor/index.tsx index e3f3030..dfd1809 100644 --- a/frontend/components/editor/index.tsx +++ b/frontend/components/editor/index.tsx @@ -1,9 +1,9 @@ "use client" -import { useEffect, useRef, useState } from "react" +import { SetStateAction, useCallback, useEffect, useRef, useState } from "react" import monaco from "monaco-editor" import Editor, { BeforeMount, OnMount } from "@monaco-editor/react" -import { io } from "socket.io-client" +import { Socket, io } from "socket.io-client" import { toast } from "sonner" import { useClerk } from "@clerk/nextjs" @@ -23,7 +23,7 @@ import Tab from "../ui/tab" import Sidebar from "./sidebar" import GenerateInput from "./generate" import { Sandbox, User, TFile, TFolder, TTab } from "@/lib/types" -import { addNew, processFileType, validateName } from "@/lib/utils" +import { addNew, processFileType, validateName, debounce } from "@/lib/utils" import { Cursors } from "./live/cursors" import { Terminal } from "@xterm/xterm" import DisableAccessModal from "./live/disableModal" @@ -41,12 +41,16 @@ export default function CodeEditor({ sandboxData: Sandbox reactDefinitionFile: string }) { - const socket = io( - `http://localhost:${process.env.NEXT_PUBLIC_SERVER_PORT}?userId=${userData.id}&sandboxId=${sandboxData.id}`, - { - timeout: 2000, - } - ) + const socketRef = useRef(null); + + // Initialize socket connection if it doesn't exist + if (!socketRef.current) { + socketRef.current = io( + `http://localhost:${process.env.NEXT_PUBLIC_SERVER_PORT}?userId=${userData.id}&sandboxId=${sandboxData.id}`, + { + timeout: 2000, + } + );} const [isPreviewCollapsed, setIsPreviewCollapsed] = useState(true) const [disableAccess, setDisableAccess] = useState({ @@ -290,26 +294,33 @@ export default function CodeEditor({ }, [decorations.options]) // Save file keybinding logic effect + const debouncedSaveData = useCallback( + debounce((value: string | undefined, activeFileId: string | undefined) => { + setTabs((prev) => + prev.map((tab) => + tab.id === activeFileId ? { ...tab, saved: true } : tab + ) + ); + console.log(`Saving file...${activeFileId}`); + console.log(`Saving file...${value}`); + socketRef.current?.emit("saveFile", activeFileId, value); + }, Number(process.env.FILE_SAVE_DEBOUNCE_DELAY)||1000), + [socketRef] + ); + useEffect(() => { const down = (e: KeyboardEvent) => { if (e.key === "s" && (e.metaKey || e.ctrlKey)) { - e.preventDefault() - - setTabs((prev) => - prev.map((tab) => - tab.id === activeFileId ? { ...tab, saved: true } : tab - ) - ) - - socket.emit("saveFile", activeFileId, editorRef?.getValue()) + e.preventDefault(); + debouncedSaveData(editorRef?.getValue(), activeFileId); } - } - document.addEventListener("keydown", down) + }; + document.addEventListener("keydown", down); return () => { - document.removeEventListener("keydown", down) - } - }, [tabs, activeFileId]) + document.removeEventListener("keydown", down); + }; + }, [activeFileId, tabs, debouncedSaveData]); // Liveblocks live collaboration setup effect useEffect(() => { @@ -358,10 +369,10 @@ export default function CodeEditor({ // Connection/disconnection effect useEffect(() => { - socket.connect() - + socketRef.current?.connect() + return () => { - socket.disconnect() + socketRef.current?.disconnect() } }, []) @@ -396,20 +407,20 @@ export default function CodeEditor({ }) } - socket.on("connect", onConnect) - socket.on("disconnect", onDisconnect) - socket.on("loaded", onLoadedEvent) - socket.on("rateLimit", onRateLimit) - socket.on("terminalResponse", onTerminalResponse) - socket.on("disableAccess", onDisableAccess) + socketRef.current?.on("connect", onConnect) + socketRef.current?.on("disconnect", onDisconnect) + socketRef.current?.on("loaded", onLoadedEvent) + socketRef.current?.on("rateLimit", onRateLimit) + socketRef.current?.on("terminalResponse", onTerminalResponse) + socketRef.current?.on("disableAccess", onDisableAccess) return () => { - socket.off("connect", onConnect) - socket.off("disconnect", onDisconnect) - socket.off("loaded", onLoadedEvent) - socket.off("rateLimit", onRateLimit) - socket.off("terminalResponse", onTerminalResponse) - socket.off("disableAccess", onDisableAccess) + socketRef.current?.off("connect", onConnect) + socketRef.current?.off("disconnect", onDisconnect) + socketRef.current?.off("loaded", onLoadedEvent) + socketRef.current?.off("rateLimit", onRateLimit) + socketRef.current?.off("terminalResponse", onTerminalResponse) + socketRef.current?.off("disableAccess", onDisableAccess) } // }, []); }, [terminals]) @@ -417,31 +428,44 @@ export default function CodeEditor({ // Helper functions for tabs: // Select file and load content - const selectFile = (tab: TTab) => { - if (tab.id === activeFileId) return - setGenerate((prev) => { - return { - ...prev, - show: false, - } - }) - const exists = tabs.find((t) => t.id === tab.id) + // Initialize debounced function once + const fileCache = useRef(new Map()); + // Debounced function to get file content + const debouncedGetFile = useCallback( + debounce((tabId, callback) => { + socketRef.current?.emit('getFile', tabId, callback); + }, 300), // 300ms debounce delay, adjust as needed + [] + ); + + const selectFile = useCallback((tab: TTab) => { + if (tab.id === activeFileId) return; + + setGenerate((prev) => ({ ...prev, show: false })); + + const exists = tabs.find((t) => t.id === tab.id); setTabs((prev) => { if (exists) { - setActiveFileId(exists.id) - return prev + setActiveFileId(exists.id); + return prev; } - return [...prev, tab] - }) + return [...prev, tab]; + }); - socket.emit("getFile", tab.id, (response: string) => { - setActiveFileContent(response) - }) - setEditorLanguage(processFileType(tab.name)) - setActiveFileId(tab.id) - } + if (fileCache.current.has(tab.id)) { + setActiveFileContent(fileCache.current.get(tab.id)); + } else { + debouncedGetFile(tab.id, (response: SetStateAction) => { + fileCache.current.set(tab.id, response); + setActiveFileContent(response); + }); + } + + setEditorLanguage(processFileType(tab.name)); + setActiveFileId(tab.id); + }, [activeFileId, tabs, debouncedGetFile]); // Close tab and remove from tabs const closeTab = (id: string) => { @@ -515,7 +539,7 @@ export default function CodeEditor({ return false } - socket.emit("renameFile", id, newName) + socketRef.current?.emit("renameFile", id, newName) setTabs((prev) => prev.map((tab) => (tab.id === id ? { ...tab, name: newName } : tab)) ) @@ -524,7 +548,7 @@ export default function CodeEditor({ } const handleDeleteFile = (file: TFile) => { - socket.emit("deleteFile", file.id, (response: (TFolder | TFile)[]) => { + socketRef.current?.emit("deleteFile", file.id, (response: (TFolder | TFile)[]) => { setFiles(response) }) closeTab(file.id) @@ -534,11 +558,11 @@ export default function CodeEditor({ setDeletingFolderId(folder.id) console.log("deleting folder", folder.id) - socket.emit("getFolder", folder.id, (response: string[]) => + socketRef.current?.emit("getFolder", folder.id, (response: string[]) => closeTabs(response) ) - socket.emit("deleteFolder", folder.id, (response: (TFolder | TFile)[]) => { + socketRef.current?.emit("deleteFolder", folder.id, (response: (TFolder | TFile)[]) => { setFiles(response) setDeletingFolderId("") }) @@ -565,7 +589,7 @@ export default function CodeEditor({ {generate.show && ai ? ( t.id === activeFileId)?.name ?? "", @@ -625,7 +649,7 @@ export default function CodeEditor({ handleRename={handleRename} handleDeleteFile={handleDeleteFile} handleDeleteFolder={handleDeleteFolder} - socket={socket} + socket={socketRef.current} setFiles={setFiles} addNew={(name, type) => addNew(name, type, setFiles, sandboxData)} deletingFolderId={deletingFolderId} @@ -757,7 +781,7 @@ export default function CodeEditor({ ) : (
@@ -772,3 +796,4 @@ export default function CodeEditor({ ) } + diff --git a/frontend/lib/utils.ts b/frontend/lib/utils.ts index c52d06b..85cc434 100644 --- a/frontend/lib/utils.ts +++ b/frontend/lib/utils.ts @@ -61,3 +61,13 @@ export function addNew( ]) } } + +export function debounce void>(func: T, wait: number): T { + let timeout: NodeJS.Timeout | null = null; + return function (...args: Parameters) { + if (timeout) { + clearTimeout(timeout); + } + timeout = setTimeout(() => func(...args), wait); + } as T; +} \ No newline at end of file