Skip to content

Commit 6790f7f

Browse files
committed
Merge branch 'main' of https://github.com/AnujaKalahara99/compiler into Dependency
2 parents bee121c + 2675822 commit 6790f7f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+6091
-1255
lines changed

Codespace_Service/src/controllers/codespaceController.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,4 +184,21 @@ export class CodespaceController {
184184
next(error);
185185
}
186186
}
187+
188+
static async createSession(req, res, next) {
189+
try {
190+
const { codespaceId, branchName } = req.body;
191+
const codespace = await CodespaceService.createBranchWithSession(
192+
codespaceId,
193+
branchName
194+
);
195+
196+
res.status(201).json({
197+
codespace,
198+
message: "Session created successfully",
199+
});
200+
} catch (error) {
201+
next(error);
202+
}
203+
}
187204
}

Codespace_Service/src/routes/codespaceRoutes.js

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@ router.get("/", CodespaceController.getCodespaces);
1616

1717
router.get("/:id", validateCodespaceId, CodespaceController.getCodespaceById);
1818

19-
router.post("/:id/share",CodespaceController.shareCodespace);
19+
router.post("/:id/share", CodespaceController.shareCodespace);
20+
21+
router.post("/session", CodespaceController.createSession);
2022

2123
router.post("/", validateCodespaceData, CodespaceController.createCodespace);
2224

@@ -26,7 +28,14 @@ router.put(
2628
validateCodespaceData,
2729
CodespaceController.updateCodespace
2830
);
29-
router.post("/:id/sharebyemail", validateCodespaceId, CodespaceController.shareCodespaceByEmail);
31+
router.post(
32+
"/:id/sharebyemail",
33+
validateCodespaceId,
34+
CodespaceController.shareCodespaceByEmail
35+
);
3036
router.delete("/:id", validateCodespaceId, CodespaceController.deleteCodespace);
31-
router.put("/accept-invitation/:invitationId", CodespaceController.acceptInvitation);
37+
router.put(
38+
"/accept-invitation/:invitationId",
39+
CodespaceController.acceptInvitation
40+
);
3241
export default router;

Codespace_Service/src/services/codespaceService.js

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,48 @@ export class CodespaceService {
127127
return true;
128128
}
129129

130+
static async createBranchWithSession(codespaceId, branchName, userId) {
131+
// await this.checkUserPermission(codespaceId, userId, ["admin", "owner", "Developer"]);
132+
133+
try {
134+
const { data, error } = await supabase.rpc("create_branch_with_session", {
135+
p_workspace_id: codespaceId,
136+
p_branch_name: branchName,
137+
});
138+
139+
if (error) {
140+
throw new Error(`Failed to create branch: ${error.message}`);
141+
}
142+
143+
return data;
144+
} catch (err) {
145+
console.error("Error in createBranchWithSession:", err);
146+
147+
if (err.message.includes("already exists")) {
148+
const duplicateError = new Error(
149+
`Branch "${branchName}" already exists in this workspace`
150+
);
151+
duplicateError.statusCode = 409;
152+
duplicateError.code = "BRANCH_ALREADY_EXISTS";
153+
throw duplicateError;
154+
}
155+
156+
if (err.message.includes("Workspace not found")) {
157+
const notFoundError = new Error("Workspace not found");
158+
notFoundError.statusCode = 404;
159+
notFoundError.code = "WORKSPACE_NOT_FOUND";
160+
throw notFoundError;
161+
}
162+
163+
const serviceError = new Error(
164+
`Failed to create branch with session: ${err.message}`
165+
);
166+
serviceError.statusCode = err.statusCode || 500;
167+
serviceError.code = err.code || "BRANCH_CREATION_FAILED";
168+
throw serviceError;
169+
}
170+
}
171+
130172
static async checkUserPermission(codespaceId, userId, allowedRoles = []) {
131173
const { data, error } = await supabase
132174
.from("workspace_members")

Frontend/src/App.tsx

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
import "./App.css";
32
import { useState, useEffect, useRef } from "react";
43
import CodeEditorPage from "./App/CodeEditor/Page";
@@ -11,11 +10,13 @@ import CodespaceInvitation from "./App/Dashboard/AcceptInvite";
1110
import ProfilePage from "./App/Dashboard/profile";
1211
import SettingsPage from "./App/Dashboard/ProfileSetting";
1312
import Homepage from "./App/Home/Homepage";
13+
import Docs from "./App/Docs/Docs";
1414
import { BrowserRouter as Router, Routes, Route, Navigate } from "react-router";
1515
import { supabase } from "./database/superbase";
1616
import { type Session, type User } from "@supabase/supabase-js";
1717
import { CodespaceProvider } from "./Contexts/CodespaceContext";
1818
import { EditorCollaborationProvider } from "./Contexts/EditorContext";
19+
import { ToastProvider } from "./Contexts/ToastContext";
1920
function App() {
2021
const [session, setSession] = useState<Session | null | undefined>(undefined);
2122
const lastTokenRef = useRef<string | undefined>(undefined);
@@ -58,7 +59,7 @@ function App() {
5859

5960
function ProtectedRoute({ children }: { children: React.ReactNode }) {
6061
if (session === undefined) {
61-
return <div></div>;
62+
return <div></div>;
6263
}
6364
return session ? children : <Navigate to="/login" />;
6465
}
@@ -72,6 +73,7 @@ function App() {
7273
<Route path="/login" element={<Login />} />
7374
<Route path="/signup" element={<Signup />} />
7475
<Route path="/homepage" element={<Homepage />} />
76+
<Route path="/docs/*" element={<Docs />} />
7577

7678
<Route
7779
path="/dashboard"
@@ -100,9 +102,11 @@ function App() {
100102
<Route
101103
path="/codeeditor/:codespaceId"
102104
element={
103-
<EditorCollaborationProvider AuthSession={session ?? null}>
104-
<CodeEditorPage />
105-
</EditorCollaborationProvider>
105+
<ToastProvider>
106+
<EditorCollaborationProvider AuthSession={session ?? null}>
107+
<CodeEditorPage />
108+
</EditorCollaborationProvider>
109+
</ToastProvider>
106110
}
107111
/>
108112

Frontend/src/App/CodeEditor/GitPanel/BranchSelector.tsx

Lines changed: 74 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,71 +1,97 @@
11
import { useState } from "react";
22
import { useTheme } from "../../../Contexts/ThemeProvider";
3-
// import type { Branch } from "./GitTypes";
4-
import { ChevronDown, GitBranch } from "lucide-react";
3+
import { ChevronDown, GitBranch, Plus } from "lucide-react";
54
import { useEditorCollaboration } from "../../../Contexts/EditorContext";
6-
7-
// interface BranchSelectorProps {
8-
// branches: Branch[];
9-
// onBranchSelect: (branchName: string) => void;
10-
// }
5+
import CreateBranch from "./CreateBranch";
116

127
const BranchSelector = () => {
138
const { theme } = useTheme();
149
const [isOpen, setIsOpen] = useState(false);
15-
const { codespace, activeSessionIndex, setActiveSessionIndex } =
16-
useEditorCollaboration();
10+
const [showCreateBranch, setShowCreateBranch] = useState(false);
11+
const {
12+
codespace,
13+
activeSessionIndex,
14+
setActiveSessionIndex,
15+
createBranchWithSession,
16+
} = useEditorCollaboration();
1717

18-
// Get the current active branch
19-
// const activeBranch = branches.find((b) => b.isActive)?.name || "main";
2018
const branchSessions = codespace?.sessions || [];
21-
console.log("Branch Sessions:", branchSessions);
22-
2319
const activeBranch = branchSessions[activeSessionIndex].name || "main";
2420

2521
const toggleDropdown = () => setIsOpen(!isOpen);
2622

27-
// const handleBranchSelect = (branchName: string) => {
28-
// onBranchSelect(branchName);
29-
// setIsOpen(false);
30-
// };
23+
const handleCreateBranch = async (branchName: string) => {
24+
setShowCreateBranch(false);
25+
createBranchWithSession(branchName);
26+
};
3127

32-
return (
33-
<div className="relative">
34-
<button
35-
className={`flex items-center justify-between w-full px-3 py-2 text-sm font-medium ${theme.surface} ${theme.border} border ${theme.text} ${theme.hover} rounded-md`}
36-
onClick={toggleDropdown}
37-
aria-haspopup="true"
38-
aria-expanded={isOpen}
39-
>
40-
<span className="flex items-center">
41-
<GitBranch className="w-4 h-4 mr-2" />
42-
{activeBranch}
43-
</span>
44-
<ChevronDown className="w-4 h-4" />
45-
</button>
28+
if (showCreateBranch) {
29+
return (
30+
<CreateBranch
31+
onCreateBranch={handleCreateBranch}
32+
onCancel={() => setShowCreateBranch(false)}
33+
/>
34+
);
35+
}
4636

47-
{isOpen && (
48-
<div
49-
className={`absolute z-10 w-full mt-1 overflow-auto rounded-md shadow-lg ${theme.surface} ${theme.border} border max-h-60`}
37+
return (
38+
<div className="space-y-2">
39+
<div className="relative">
40+
<button
41+
className={`flex items-center justify-between w-full px-3 py-2 text-sm font-medium ${theme.surface} ${theme.border} border ${theme.text} ${theme.hover} rounded-md`}
42+
onClick={toggleDropdown}
43+
aria-haspopup="true"
44+
aria-expanded={isOpen}
5045
>
51-
<ul className="py-1 text-sm" role="menu" aria-orientation="vertical">
52-
{branchSessions.map((branch, index) => (
53-
<li key={branch.branchId}>
46+
<span className="flex items-center">
47+
<GitBranch className="w-4 h-4 mr-2" />
48+
{activeBranch}
49+
</span>
50+
<ChevronDown className="w-4 h-4" />
51+
</button>
52+
53+
{isOpen && (
54+
<div
55+
className={`absolute z-10 w-full mt-1 overflow-auto rounded-md shadow-lg ${theme.surface} ${theme.border} border max-h-60`}
56+
>
57+
<ul
58+
className="py-1 text-sm"
59+
role="menu"
60+
aria-orientation="vertical"
61+
>
62+
{branchSessions.map((branch, index) => {
63+
return (
64+
<li key={branch.branchId}>
65+
<button
66+
className={`block w-full text-left px-4 py-2 ${
67+
theme.text
68+
} ${index === activeSessionIndex ? theme.active : ""} ${
69+
theme.hover
70+
}`}
71+
role="menuitem"
72+
onClick={() => setActiveSessionIndex(index)}
73+
>
74+
{branch.name}
75+
</button>
76+
</li>
77+
);
78+
})}
79+
<li className={`border-t ${theme.border}`}>
5480
<button
55-
className={`block w-full text-left px-4 py-2 ${theme.text} ${
56-
index === activeSessionIndex ? theme.active : ""
57-
} ${theme.hover}`}
58-
role="menuitem"
59-
// onClick={() => handleBranchSelect(branch.name)}
60-
onClick={() => setActiveSessionIndex(index)}
81+
className={`flex items-center w-full text-left px-4 py-2 ${theme.text} ${theme.hover}`}
82+
onClick={() => {
83+
setShowCreateBranch(true);
84+
setIsOpen(false);
85+
}}
6186
>
62-
{branch.name}
87+
<Plus className="w-4 h-4 mr-2" />
88+
Create new branch
6389
</button>
6490
</li>
65-
))}
66-
</ul>
67-
</div>
68-
)}
91+
</ul>
92+
</div>
93+
)}
94+
</div>
6995
</div>
7096
);
7197
};
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import { useState } from "react";
2+
import { useTheme } from "../../../Contexts/ThemeProvider";
3+
import { GitBranch, Plus, X } from "lucide-react";
4+
5+
interface CreateBranchProps {
6+
onCreateBranch: (branchName: string) => void;
7+
onCancel?: () => void;
8+
}
9+
10+
const CreateBranch = ({ onCreateBranch, onCancel }: CreateBranchProps) => {
11+
const { theme } = useTheme();
12+
const [branchName, setBranchName] = useState("");
13+
const [isCreating, setIsCreating] = useState(false);
14+
15+
const handleSubmit = async (e: React.FormEvent) => {
16+
e.preventDefault();
17+
if (!branchName.trim()) return;
18+
19+
setIsCreating(true);
20+
try {
21+
await onCreateBranch(branchName.trim());
22+
setBranchName("");
23+
onCancel?.();
24+
} catch (error) {
25+
console.error("Failed to create branch:", error);
26+
} finally {
27+
setIsCreating(false);
28+
}
29+
};
30+
31+
const handleCancel = () => {
32+
setBranchName("");
33+
onCancel?.();
34+
};
35+
36+
return (
37+
<div className={`p-4 ${theme.surface} ${theme.border} border rounded-md`}>
38+
<div className="flex items-center mb-3">
39+
<GitBranch className="w-4 h-4 mr-2" />
40+
<h3 className={`text-sm font-medium ${theme.text}`}>
41+
Create New Branch
42+
</h3>
43+
</div>
44+
45+
<form onSubmit={handleSubmit} className="space-y-3">
46+
<div>
47+
<input
48+
type="text"
49+
value={branchName}
50+
onChange={(e) => setBranchName(e.target.value)}
51+
placeholder="Enter branch name..."
52+
className={`w-full px-3 py-2 text-sm ${theme.surface} ${theme.border} border ${theme.text} rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500`}
53+
disabled={isCreating}
54+
autoFocus
55+
/>
56+
</div>
57+
58+
<div className="flex justify-end space-x-2">
59+
<button
60+
type="button"
61+
onClick={handleCancel}
62+
className={`flex items-center px-3 py-2 text-sm font-medium ${theme.text} ${theme.hover} rounded-md`}
63+
disabled={isCreating}
64+
>
65+
<X className="w-4 h-4 mr-1" />
66+
Cancel
67+
</button>
68+
69+
<button
70+
type="submit"
71+
disabled={!branchName.trim() || isCreating}
72+
className={`flex items-center px-3 py-2 text-sm font-medium bg-blue-600 text-white rounded-md hover:bg-blue-700 disabled:opacity-50 disabled:cursor-not-allowed`}
73+
>
74+
<Plus className="w-4 h-4 mr-1" />
75+
{isCreating ? "Creating..." : "Create"}
76+
</button>
77+
</div>
78+
</form>
79+
</div>
80+
);
81+
};
82+
83+
export default CreateBranch;

0 commit comments

Comments
 (0)