diff --git a/backend/database/src/index.ts b/backend/database/src/index.ts
index b115fb5..604b093 100644
--- a/backend/database/src/index.ts
+++ b/backend/database/src/index.ts
@@ -94,7 +94,6 @@ export default {
const initStorageRes = await env.STORAGE.fetch(initStorageRequest);
const initStorage = await initStorageRes.text();
- console.log("initStorage: ", initStorage);
return new Response(sb.id, { status: 200 });
} else {
diff --git a/backend/server/src/index.ts b/backend/server/src/index.ts
index dde30a1..a13d39c 100644
--- a/backend/server/src/index.ts
+++ b/backend/server/src/index.ts
@@ -39,6 +39,7 @@ const io = new Server(httpServer, {
})
let inactivityTimeout: NodeJS.Timeout | null = null;
+let isOwnerConnected = false;
const terminals: {
[id: string]: { terminal: IPty; onData: IDisposable; onExit: IDisposable }
@@ -58,7 +59,7 @@ io.use(async (socket, next) => {
const parseQuery = handshakeSchema.safeParse(q)
if (!parseQuery.success) {
- console.log("Invalid request.")
+ ("Invalid request.")
next(new Error("Invalid request."))
return
}
@@ -68,7 +69,6 @@ io.use(async (socket, next) => {
const dbUserJSON = (await dbUser.json()) as User
if (!dbUserJSON) {
- console.log("DB error.")
next(new Error("DB error."))
return
}
@@ -79,7 +79,6 @@ io.use(async (socket, next) => {
)
if (!sandbox && !sharedSandboxes) {
- console.log("Invalid credentials.")
next(new Error("Invalid credentials."))
return
}
@@ -103,6 +102,15 @@ io.on("connection", async (socket) => {
isOwner: boolean
}
+ if (data.isOwner) {
+ isOwnerConnected = true
+ } else {
+ if (!isOwnerConnected) {
+ socket.emit("disableAccess", "The sandbox owner is not connected.")
+ return
+ }
+ }
+
const sandboxFiles = await getSandboxFiles(data.sandboxId)
sandboxFiles.fileData.forEach((file) => {
const filePath = path.join(dirName, file.id)
@@ -224,12 +232,7 @@ io.on("connection", async (socket) => {
socket.on("createTerminal", (id: string, callback) => {
console.log("creating terminal", id)
- if (terminals[id]) {
- console.log("Terminal already exists.")
- return
- }
- if (Object.keys(terminals).length >= 4) {
- console.log("Too many terminals.")
+ if (terminals[id] || Object.keys(terminals).length >= 4) {
return
}
@@ -240,9 +243,7 @@ io.on("connection", async (socket) => {
})
const onData = pty.onData((data) => {
- console.log("ondata")
socket.emit("terminalResponse", {
- // data: Buffer.from(data, "utf-8").toString("base64"),
id,
data,
})
@@ -263,7 +264,6 @@ io.on("connection", async (socket) => {
socket.on("terminalData", (id: string, data: string) => {
if (!terminals[id]) {
- console.log("terminals", terminals)
return
}
@@ -276,7 +276,6 @@ io.on("connection", async (socket) => {
socket.on("closeTerminal", (id: string, callback) => {
if (!terminals[id]) {
- console.log("tried to close, but term does not exist. terminals", terminals)
return
}
@@ -332,11 +331,7 @@ io.on("connection", async (socket) => {
delete terminals[t[0]]
})
- // console.log("The owner disconnected.")
- socket.broadcast.emit("ownerDisconnected")
- }
- else {
- // console.log("A shared user disconnected.")
+ socket.broadcast.emit("disableAccess", "The sandbox owner has disconnected.")
}
const sockets = await io.fetchSockets()
diff --git a/backend/server/src/utils.ts b/backend/server/src/utils.ts
index e07b69c..eb660c6 100644
--- a/backend/server/src/utils.ts
+++ b/backend/server/src/utils.ts
@@ -16,7 +16,6 @@ export const getSandboxFiles = async (id: string) => {
const paths = sandboxData.objects.map((obj) => obj.key)
const processedFiles = await processFiles(paths, id)
- // console.log("processedFiles.fileData:", processedFiles.fileData)
return processedFiles
}
@@ -27,7 +26,6 @@ const processFiles = async (paths: string[], id: string) => {
paths.forEach((path) => {
const allParts = path.split("/")
if (allParts[1] !== id) {
- console.log("invalid path!!!!")
return
}
diff --git a/frontend/app/(app)/layout.tsx b/frontend/app/(app)/layout.tsx
index 973ec9e..dad9bc4 100644
--- a/frontend/app/(app)/layout.tsx
+++ b/frontend/app/(app)/layout.tsx
@@ -1,22 +1,22 @@
-import { User } from "@/lib/types"
-import { currentUser } from "@clerk/nextjs"
-import { redirect } from "next/navigation"
+import { User } from "@/lib/types";
+import { currentUser } from "@clerk/nextjs";
+import { redirect } from "next/navigation";
export default async function AppAuthLayout({
children,
}: {
- children: React.ReactNode
+ children: React.ReactNode;
}) {
- const user = await currentUser()
+ const user = await currentUser();
if (!user) {
- redirect("/")
+ redirect("/");
}
const dbUser = await fetch(
`https://database.ishaan1013.workers.dev/api/user?id=${user.id}`
- )
- const dbUserJSON = (await dbUser.json()) as User
+ );
+ const dbUserJSON = (await dbUser.json()) as User;
if (!dbUserJSON.id) {
const res = await fetch(
@@ -32,12 +32,8 @@ export default async function AppAuthLayout({
email: user.emailAddresses[0].emailAddress,
}),
}
- )
-
- console.log(res)
- } else {
- // user already exists in db
+ );
}
- return <>{children}>
+ return <>{children}>;
}
diff --git a/frontend/components/dashboard/navbar/search.tsx b/frontend/components/dashboard/navbar/search.tsx
index a223610..65e731f 100644
--- a/frontend/components/dashboard/navbar/search.tsx
+++ b/frontend/components/dashboard/navbar/search.tsx
@@ -1,26 +1,25 @@
-"use client"
+"use client";
-import { Input } from "../../ui/input"
-import { Search } from "lucide-react"
-import { useEffect, useState } from "react"
-import { useRouter } from "next/navigation"
+import { Input } from "../../ui/input";
+import { Search } from "lucide-react";
+import { useEffect, useState } from "react";
+import { useRouter } from "next/navigation";
export default function DashboardNavbarSearch() {
- const [search, setSearch] = useState("")
- const router = useRouter()
+ const [search, setSearch] = useState("");
+ const router = useRouter();
useEffect(() => {
const delayDebounceFn = setTimeout(() => {
- console.log("SEARCH", search)
if (search) {
- router.push(`/dashboard?q=${search}`)
+ router.push(`/dashboard?q=${search}`);
} else {
- router.push(`/dashboard`)
+ router.push(`/dashboard`);
}
- }, 300)
+ }, 300);
- return () => clearTimeout(delayDebounceFn)
- }, [search])
+ return () => clearTimeout(delayDebounceFn);
+ }, [search]);
return (
@@ -32,5 +31,5 @@ export default function DashboardNavbarSearch() {
className="pl-8"
/>
- )
+ );
}
diff --git a/frontend/components/editor/index.tsx b/frontend/components/editor/index.tsx
index 195f75b..85b34e9 100644
--- a/frontend/components/editor/index.tsx
+++ b/frontend/components/editor/index.tsx
@@ -88,7 +88,6 @@ export default function CodeEditor({
const clerk = useClerk();
const room = useRoom();
const activeTerminal = terminals.find((t) => t.id === activeTerminalId);
- console.log("activeTerminal", activeTerminal ? activeTerminal.id : "none");
// const editorRef = useRef(null)
const [editorRef, setEditorRef] =
@@ -270,9 +269,6 @@ export default function CodeEditor({
if (e.key === "s" && (e.metaKey || e.ctrlKey)) {
e.preventDefault();
- // const activeTab = tabs.find((t) => t.id === activeFileId)
- // console.log("saving:", activeTab?.name, editorRef?.getValue())
-
setTabs((prev) =>
prev.map((tab) =>
tab.id === activeFileId ? { ...tab, saved: true } : tab
@@ -367,7 +363,11 @@ export default function CodeEditor({
createTerminal();
};
- const onDisconnect = () => {};
+ const onDisconnect = () => {
+ console.log("disconnected");
+
+ closeAllTerminals();
+ };
const onLoadedEvent = (files: (TFolder | TFile)[]) => {
setFiles(files);
@@ -385,11 +385,19 @@ export default function CodeEditor({
if (term && term.terminal) term.terminal.write(res);
};
+ const onDisableAccess = (message: string) => {
+ setDisableAccess({
+ isDisabled: true,
+ message,
+ });
+ };
+
socket.on("connect", onConnect);
socket.on("disconnect", onDisconnect);
socket.on("loaded", onLoadedEvent);
socket.on("rateLimit", onRateLimit);
socket.on("terminalResponse", onTerminalResponse);
+ socket.on("disableAccess", onDisableAccess);
return () => {
socket.off("connect", onConnect);
@@ -397,6 +405,7 @@ export default function CodeEditor({
socket.off("loaded", onLoadedEvent);
socket.off("rateLimit", onRateLimit);
socket.off("terminalResponse", onTerminalResponse);
+ socket.off("disableAccess", onDisableAccess);
};
}, []);
@@ -492,6 +501,13 @@ export default function CodeEditor({
});
};
+ const closeAllTerminals = () => {
+ terminals.forEach((term) => {
+ socket.emit("closeTerminal", term.id, () => {}); // no need to wait for response here
+ setTerminals((prev) => prev.filter((t) => t.id !== term.id));
+ });
+ };
+
const handleRename = (
id: string,
newName: string,
diff --git a/frontend/components/editor/live/disableModal.tsx b/frontend/components/editor/live/disableModal.tsx
index b66d369..1056b42 100644
--- a/frontend/components/editor/live/disableModal.tsx
+++ b/frontend/components/editor/live/disableModal.tsx
@@ -9,7 +9,15 @@ import {
DialogTrigger,
} from "@/components/ui/dialog";
-import { ChevronRight, FileStack, Globe, TextCursor } from "lucide-react";
+import {
+ ChevronRight,
+ FileStack,
+ Globe,
+ Loader2,
+ TextCursor,
+} from "lucide-react";
+import { useRouter } from "next/navigation";
+import { useEffect } from "react";
export default function DisableAccessModal({
open,
@@ -20,13 +28,30 @@ export default function DisableAccessModal({
setOpen: (open: boolean) => void;
message: string;
}) {
+ const router = useRouter();
+
+ useEffect(() => {
+ if (open) {
+ const timeout = setTimeout(() => {
+ router.push("/dashboard");
+ }, 5000);
+ return () => clearTimeout(timeout);
+ }
+ }, []);
+
return (
);
diff --git a/frontend/components/editor/navbar/edit.tsx b/frontend/components/editor/navbar/edit.tsx
index c5316fb..17575d7 100644
--- a/frontend/components/editor/navbar/edit.tsx
+++ b/frontend/components/editor/navbar/edit.tsx
@@ -1,4 +1,4 @@
-"use client"
+"use client";
import {
Dialog,
@@ -7,10 +7,10 @@ import {
DialogHeader,
DialogTitle,
DialogTrigger,
-} from "@/components/ui/dialog"
-import { z } from "zod"
-import { zodResolver } from "@hookform/resolvers/zod"
-import { useForm } from "react-hook-form"
+} from "@/components/ui/dialog";
+import { z } from "zod";
+import { zodResolver } from "@hookform/resolvers/zod";
+import { useForm } from "react-hook-form";
import {
Form,
@@ -20,41 +20,41 @@ import {
FormItem,
FormLabel,
FormMessage,
-} from "@/components/ui/form"
-import { Input } from "@/components/ui/input"
+} from "@/components/ui/form";
+import { Input } from "@/components/ui/input";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
-} from "@/components/ui/select"
-import { Loader2 } from "lucide-react"
-import { useState } from "react"
-import { Sandbox } from "@/lib/types"
-import { Button } from "@/components/ui/button"
-import { deleteSandbox, updateSandbox } from "@/lib/actions"
-import { useRouter } from "next/navigation"
-import { toast } from "sonner"
+} from "@/components/ui/select";
+import { Loader2 } from "lucide-react";
+import { useState } from "react";
+import { Sandbox } from "@/lib/types";
+import { Button } from "@/components/ui/button";
+import { deleteSandbox, updateSandbox } from "@/lib/actions";
+import { useRouter } from "next/navigation";
+import { toast } from "sonner";
const formSchema = z.object({
name: z.string().min(1).max(16),
visibility: z.enum(["public", "private"]),
-})
+});
export default function EditSandboxModal({
open,
setOpen,
data,
}: {
- open: boolean
- setOpen: (open: boolean) => void
- data: Sandbox
+ open: boolean;
+ setOpen: (open: boolean) => void;
+ data: Sandbox;
}) {
- const [loading, setLoading] = useState(false)
- const [loadingDelete, setLoadingDelete] = useState(false)
+ const [loading, setLoading] = useState(false);
+ const [loadingDelete, setLoadingDelete] = useState(false);
- const router = useRouter()
+ const router = useRouter();
const form = useForm>({
resolver: zodResolver(formSchema),
@@ -62,24 +62,22 @@ export default function EditSandboxModal({
name: data.name,
visibility: data.visibility,
},
- })
+ });
async function onSubmit(values: z.infer) {
- console.log(values)
+ setLoading(true);
+ await updateSandbox({ id: data.id, ...values });
- setLoading(true)
- await updateSandbox({ id: data.id, ...values })
+ toast.success("Sandbox updated successfully");
- toast.success("Sandbox updated successfully")
-
- setLoading(false)
+ setLoading(false);
}
async function onDelete() {
- setLoadingDelete(true)
- await deleteSandbox(data.id)
+ setLoadingDelete(true);
+ await deleteSandbox(data.id);
- router.push("/dashboard")
+ router.push("/dashboard");
}
return (
@@ -155,5 +153,5 @@ export default function EditSandboxModal({
- )
+ );
}
diff --git a/frontend/components/editor/sidebar/file.tsx b/frontend/components/editor/sidebar/file.tsx
index e483033..1f4db2e 100644
--- a/frontend/components/editor/sidebar/file.tsx
+++ b/frontend/components/editor/sidebar/file.tsx
@@ -1,16 +1,16 @@
-"use client"
+"use client";
-import Image from "next/image"
-import { getIconForFile } from "vscode-icons-js"
-import { TFile, TTab } from "@/lib/types"
-import { useEffect, useRef, useState } from "react"
+import Image from "next/image";
+import { getIconForFile } from "vscode-icons-js";
+import { TFile, TTab } from "@/lib/types";
+import { useEffect, useRef, useState } from "react";
import {
ContextMenu,
ContextMenuContent,
ContextMenuItem,
ContextMenuTrigger,
-} from "@/components/ui/context-menu"
-import { Loader2, Pencil, Trash2 } from "lucide-react"
+} from "@/components/ui/context-menu";
+import { Loader2, Pencil, Trash2 } from "lucide-react";
export default function SidebarFile({
data,
@@ -18,29 +18,26 @@ export default function SidebarFile({
handleRename,
handleDeleteFile,
}: {
- data: TFile
- selectFile: (file: TTab) => void
+ data: TFile;
+ selectFile: (file: TTab) => void;
handleRename: (
id: string,
newName: string,
oldName: string,
type: "file" | "folder"
- ) => boolean
- handleDeleteFile: (file: TFile) => void
+ ) => boolean;
+ handleDeleteFile: (file: TFile) => void;
}) {
- const [imgSrc, setImgSrc] = useState(`/icons/${getIconForFile(data.name)}`)
- const [editing, setEditing] = useState(false)
- const inputRef = useRef(null)
- const [pendingDelete, setPendingDelete] = useState(false)
+ const [imgSrc, setImgSrc] = useState(`/icons/${getIconForFile(data.name)}`);
+ const [editing, setEditing] = useState(false);
+ const inputRef = useRef(null);
+ const [pendingDelete, setPendingDelete] = useState(false);
useEffect(() => {
if (editing) {
- setTimeout(() => inputRef.current?.focus(), 0)
+ setTimeout(() => inputRef.current?.focus(), 0);
}
- if (!inputRef.current) {
- console.log("no input ref")
- }
- }, [editing, inputRef.current])
+ }, [editing, inputRef.current]);
const renameFile = () => {
const renamed = handleRename(
@@ -48,19 +45,19 @@ export default function SidebarFile({
inputRef.current?.value ?? data.name,
data.name,
"file"
- )
+ );
if (!renamed && inputRef.current) {
- inputRef.current.value = data.name
+ inputRef.current.value = data.name;
}
- setEditing(false)
- }
+ setEditing(false);
+ };
return (
{
- if (!editing && !pendingDelete) selectFile({ ...data, saved: true })
+ if (!editing && !pendingDelete) selectFile({ ...data, saved: true });
}}
// onDoubleClick={() => {
// setEditing(true)
@@ -83,8 +80,8 @@ export default function SidebarFile({
) : (
- )
+ );
}
diff --git a/frontend/components/editor/sidebar/folder.tsx b/frontend/components/editor/sidebar/folder.tsx
index 7c47059..6a1d148 100644
--- a/frontend/components/editor/sidebar/folder.tsx
+++ b/frontend/components/editor/sidebar/folder.tsx
@@ -1,17 +1,17 @@
-"use client"
+"use client";
-import Image from "next/image"
-import { useEffect, useRef, useState } from "react"
-import { getIconForFolder, getIconForOpenFolder } from "vscode-icons-js"
-import { TFile, TFolder, TTab } from "@/lib/types"
-import SidebarFile from "./file"
+import Image from "next/image";
+import { useEffect, useRef, useState } from "react";
+import { getIconForFolder, getIconForOpenFolder } from "vscode-icons-js";
+import { TFile, TFolder, TTab } from "@/lib/types";
+import SidebarFile from "./file";
import {
ContextMenu,
ContextMenuContent,
ContextMenuItem,
ContextMenuTrigger,
-} from "@/components/ui/context-menu"
-import { Pencil, Trash2 } from "lucide-react"
+} from "@/components/ui/context-menu";
+import { Pencil, Trash2 } from "lucide-react";
export default function SidebarFolder({
data,
@@ -20,30 +20,30 @@ export default function SidebarFolder({
handleDeleteFile,
handleDeleteFolder,
}: {
- data: TFolder
- selectFile: (file: TTab) => void
+ data: TFolder;
+ selectFile: (file: TTab) => void;
handleRename: (
id: string,
newName: string,
oldName: string,
type: "file" | "folder"
- ) => boolean
- handleDeleteFile: (file: TFile) => void
- handleDeleteFolder: (folder: TFolder) => void
+ ) => boolean;
+ handleDeleteFile: (file: TFile) => void;
+ handleDeleteFolder: (folder: TFolder) => void;
}) {
- const [isOpen, setIsOpen] = useState(false)
+ const [isOpen, setIsOpen] = useState(false);
const folder = isOpen
? getIconForOpenFolder(data.name)
- : getIconForFolder(data.name)
+ : getIconForFolder(data.name);
- const [editing, setEditing] = useState(false)
- const inputRef = useRef(null)
+ const [editing, setEditing] = useState(false);
+ const inputRef = useRef(null);
useEffect(() => {
if (editing) {
- inputRef.current?.focus()
+ inputRef.current?.focus();
}
- }, [editing])
+ }, [editing]);
return (
@@ -60,9 +60,8 @@ export default function SidebarFolder({
/>
@@ -82,8 +80,7 @@ export default function SidebarFolder({
{
- console.log("rename")
- setEditing(true)
+ setEditing(true);
}}
>
@@ -92,7 +89,7 @@ export default function SidebarFolder({
{
- console.log("delete")
+ console.log("delete");
// setPendingDelete(true)
// handleDeleteFile(data)
}}
@@ -129,5 +126,5 @@ export default function SidebarFolder({
) : null}
- )
+ );
}
diff --git a/frontend/components/editor/sidebar/index.tsx b/frontend/components/editor/sidebar/index.tsx
index acb3df3..0c725dd 100644
--- a/frontend/components/editor/sidebar/index.tsx
+++ b/frontend/components/editor/sidebar/index.tsx
@@ -1,14 +1,14 @@
-"use client"
+"use client";
-import { FilePlus, FolderPlus, Loader2, Search, Sparkles } from "lucide-react"
-import SidebarFile from "./file"
-import SidebarFolder from "./folder"
-import { TFile, TFolder, TTab } from "@/lib/types"
-import { useState } from "react"
-import New from "./new"
-import { Socket } from "socket.io-client"
-import Button from "@/components/ui/customButton"
-import { Switch } from "@/components/ui/switch"
+import { FilePlus, FolderPlus, Loader2, Search, Sparkles } from "lucide-react";
+import SidebarFile from "./file";
+import SidebarFolder from "./folder";
+import { TFile, TFolder, TTab } from "@/lib/types";
+import { useState } from "react";
+import New from "./new";
+import { Socket } from "socket.io-client";
+import Button from "@/components/ui/customButton";
+import { Switch } from "@/components/ui/switch";
export default function Sidebar({
files,
@@ -21,22 +21,24 @@ export default function Sidebar({
ai,
setAi,
}: {
- files: (TFile | TFolder)[]
- selectFile: (tab: TTab) => void
+ files: (TFile | TFolder)[];
+ selectFile: (tab: TTab) => void;
handleRename: (
id: string,
newName: string,
oldName: string,
type: "file" | "folder"
- ) => boolean
- handleDeleteFile: (file: TFile) => void
- handleDeleteFolder: (folder: TFolder) => void
- socket: Socket
- addNew: (name: string, type: "file" | "folder") => void
- ai: boolean
- setAi: React.Dispatch>
+ ) => boolean;
+ handleDeleteFile: (file: TFile) => void;
+ handleDeleteFolder: (folder: TFolder) => void;
+ socket: Socket;
+ addNew: (name: string, type: "file" | "folder") => void;
+ ai: boolean;
+ setAi: React.Dispatch>;
}) {
- const [creatingNew, setCreatingNew] = useState<"file" | "folder" | null>(null)
+ const [creatingNew, setCreatingNew] = useState<"file" | "folder" | null>(
+ null
+ );
return (
@@ -94,8 +96,7 @@ export default function Sidebar({
socket={socket}
type={creatingNew}
stopEditing={() => {
- console.log("stopped editing")
- setCreatingNew(null)
+ setCreatingNew(null);
}}
addNew={addNew}
/>
@@ -119,5 +120,5 @@ export default function Sidebar({
- )
+ );
}
diff --git a/frontend/components/editor/terminal/index.tsx b/frontend/components/editor/terminal/index.tsx
index 73fb3d9..81831d7 100644
--- a/frontend/components/editor/terminal/index.tsx
+++ b/frontend/components/editor/terminal/index.tsx
@@ -51,7 +51,6 @@ export default function EditorTerminal({
setTerm(term);
}
const disposable = term.onData((data) => {
- console.log("sending data", data);
socket.emit("terminalData", id, data);
});