Skip to content

Commit a5480ea

Browse files
author
joeldevelops
committed
Add project dashboard
1 parent f362e65 commit a5480ea

File tree

11 files changed

+661
-9
lines changed

11 files changed

+661
-9
lines changed

package-lock.json

Lines changed: 40 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/app/package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,11 @@
1919
"@dagrejs/dagre": "^1.1.4",
2020
"@radix-ui/themes": "^3.1.6",
2121
"@xyflow/react": "^12.3.6",
22+
"chart.js": "^4.4.7",
2223
"react": "^19.0.0",
24+
"react-chartjs-2": "^5.3.0",
2325
"react-dom": "^19.0.0",
26+
"react-icons": "^5.4.0",
2427
"react-router": "^7.1.1",
2528
"react-toastify": "^11.0.0"
2629
}

packages/app/src/main.tsx

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,16 @@ import Audit from "./pages/audit/index";
1717
import AuditFile from "./pages/audit/file";
1818
import DashboardPage from "./pages/dashboard";
1919
import ProjectsPage from "./pages/projects";
20+
import Project from "./pages/project";
2021
import WorkspacesPage from "./pages/workspaces";
2122
import Auth from "./pages/auth";
2223
import Index from "./pages";
2324

25+
const reactFlowPaths = [
26+
"/splitConfigure",
27+
"/audit",
28+
];
29+
2430
const router = createBrowserRouter([
2531
{
2632
path: "/",
@@ -38,6 +44,18 @@ const router = createBrowserRouter([
3844
path: "/projects",
3945
element: <ProjectsPage />,
4046
},
47+
{
48+
path: "/project/:id/overview",
49+
element: <Project />,
50+
},
51+
{
52+
path: "/project/:id/splitConfigure", // Shows react flow
53+
element: <Project />,
54+
},
55+
{
56+
path: "/project/:id/audit", // Shows react flow
57+
element: <Project />,
58+
},
4159
{
4260
path: "/workspaces",
4361
element: <WorkspacesPage />,
@@ -79,7 +97,12 @@ if (!rootElement) {
7997
function Main() {
8098
const themeContext = useContext(ThemeContext);
8199

82-
const shouldRenderReactFlow = !window.location.pathname.startsWith("/projects");
100+
let shouldRenderReactFlow = false;
101+
reactFlowPaths.forEach((path) => {
102+
if (window.location.pathname.includes(path)) {
103+
shouldRenderReactFlow = true;
104+
}
105+
});
83106

84107
return (
85108
<Theme appearance={themeContext.theme}>

packages/app/src/pages/dashboard/Dashboard.tsx

Lines changed: 152 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
2+
3+
export default function ProjectAudit() {
4+
return (
5+
<div className="flex gap-x-2 min-h-screen text-white bg-background-light dark:bg-background-dark p-2">
6+
</div>
7+
);
8+
}

packages/app/src/pages/project/ProjectOverview.tsx

Lines changed: 275 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import { useEffect, useState } from "react";
2+
import { useLocation, useParams } from "react-router";
3+
import { SegmentedControl } from "@radix-ui/themes";
4+
5+
import ChangeThemeButton from "../../components/ChangeThemeButton"
6+
import AccountMenu from "../../components/AccountMenu"
7+
8+
import ProjectOverview from "./ProjectOverview";
9+
import ProjectSplitConfigure from "./ProjectSplitConfigure";
10+
import ProjectAudit from "./ProjectAudit";
11+
import { Project } from "../../types";
12+
13+
export default function ProjectPage(props: {
14+
project: Project;
15+
}) {
16+
const location = useLocation();
17+
const { id } = useParams();
18+
19+
const getActiveDefaultValue = () => {
20+
if (location.pathname.includes("splitConfigure")) {
21+
return "api";
22+
} else if (location.pathname.includes("audit")) {
23+
return "audit";
24+
}
25+
return "overview";
26+
}
27+
28+
const [activePage, setActivePage] = useState(getActiveDefaultValue());
29+
30+
const handleSegmentedControlChange = (e: any, route: string) => {
31+
e.preventDefault();
32+
window.location.pathname = route;
33+
}
34+
35+
useEffect(() => {
36+
// Force reload on route change
37+
setActivePage(getActiveDefaultValue());
38+
}, []);
39+
40+
41+
return (
42+
<div className="w-full text-text-light dark:text-white bg-secondaryBackground-light dark:bg-secondaryBackground-dark rounded-xl flex flex-col">
43+
{/* Top bar with project search on the left and the account icon on the right */}
44+
<div className="flex justify-between p-2 border-b-[1px] border-foreground-light dark:border-foreground-dark">
45+
<div>
46+
<SegmentedControl.Root defaultValue={activePage} size="3" variant="classic" onValueChange={(e) => setActivePage(e)}>
47+
<SegmentedControl.Item
48+
value="overview"
49+
onClick={(e) => handleSegmentedControlChange(e, `/project/${id}/overview`)}
50+
>Overview</SegmentedControl.Item>
51+
<SegmentedControl.Item
52+
value="api"
53+
onClick={(e) => handleSegmentedControlChange(e, `/project/${id}/splitConfigure`)}
54+
>API</SegmentedControl.Item>
55+
<SegmentedControl.Item
56+
value="audit"
57+
onClick={(e) => handleSegmentedControlChange(e, `/project/${id}/audit`)}
58+
>Audit</SegmentedControl.Item>
59+
</SegmentedControl.Root>
60+
</div>
61+
<div className="flex gap-x-2">
62+
<ChangeThemeButton />
63+
<AccountMenu />
64+
</div>
65+
</div>
66+
<div className="flex flex-col p-4">
67+
<div className="flex flex-col gap-y-2">
68+
<h1 className="text-2xl font-bold">{props.project.name}</h1>
69+
</div>
70+
</div>
71+
{/* Overview */}
72+
{getActiveDefaultValue() === "overview" && <ProjectOverview project={props.project} />}
73+
{/* Split Configure */}
74+
{getActiveDefaultValue() === "api" && <ProjectSplitConfigure />}
75+
{/* Audit */}
76+
{getActiveDefaultValue() === "audit" && <ProjectAudit />}
77+
</div>
78+
);
79+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
2+
3+
export default function ProjectSplitConfigure() {
4+
return (
5+
<div className="flex gap-x-2 min-h-screen text-white bg-background-light dark:bg-background-dark p-2">
6+
</div>
7+
);
8+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import { useParams } from "react-router";
2+
import AppSidebar from "../../components/Sidebar/AppSidebar";
3+
import ProjectPage from "./ProjectPage";
4+
import { type Project } from "../../types";
5+
6+
const projectsList: Project[] = [{
7+
id: 1,
8+
name: "Frontend",
9+
updatedAt: new Date().toISOString(),
10+
createdAt: new Date().toISOString(),
11+
language: "TypeScript",
12+
},{
13+
id: 2,
14+
name: "Listener",
15+
updatedAt: new Date().toISOString(),
16+
createdAt: new Date().toISOString(),
17+
language: "javascript",
18+
},{
19+
id: 3,
20+
name: "AI Model",
21+
updatedAt: new Date().toISOString(),
22+
createdAt: new Date().toISOString(),
23+
language: "python",
24+
},{
25+
id: 4,
26+
name: "Backend",
27+
updatedAt: new Date().toISOString(),
28+
createdAt: new Date().toISOString(),
29+
language: "nodejs",
30+
},{
31+
id: 5,
32+
name: "Engine",
33+
updatedAt: new Date().toISOString(),
34+
createdAt: new Date().toISOString(),
35+
language: "csharp",
36+
},{
37+
id: 6,
38+
name: "Optimus",
39+
updatedAt: new Date().toISOString(),
40+
createdAt: new Date().toISOString(),
41+
language: "TypeScript",
42+
}, ]
43+
44+
export default function Project() {
45+
const { id } = useParams();
46+
const project = projectsList.find((project) => project.id === Number(id));
47+
48+
return (
49+
<div className="flex gap-x-2 min-h-screen text-white bg-background-light dark:bg-background-dark p-2">
50+
<AppSidebar />
51+
<ProjectPage project={project as Project} />
52+
</div>
53+
);
54+
}

packages/app/src/pages/projects/ProjectCard.tsx

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,18 @@
1+
import { useNavigate } from 'react-router'
12
import { Project } from '../../types'
23

34
export default function ProjectCard(project: Project) {
5+
const navigate = useNavigate()
6+
7+
const handleNavigate = (e: any) => {
8+
e.preventDefault()
9+
navigate(`/project/${project.id}/overview`)
10+
}
11+
412
return (
5-
<div className="relative flex flex-col bg-foreground-light dark:bg-foreground-dark rounded-lg border-[1px] border-borderLight dark:border-border-darkPurple cursor-pointer hover:shadow-lg hover:mt-[-2px] hover:mb-[2px] transition-all">
13+
<div
14+
onClick={(e) => handleNavigate(e)}
15+
className="relative flex flex-col bg-foreground-light dark:bg-foreground-dark rounded-lg border-[1px] border-borderLight dark:border-border-darkPurple cursor-pointer hover:shadow-lg hover:mt-[-2px] hover:mb-[2px] transition-all">
616
<div className="absolute top-4 right-4 border-[1px] bg-foreground-light dark:bg-foreground-dark border-border-light dark:border-border-darkGray rounded-xl hover:bg-hover-light dark:hover:bg-hover-mid">
717
<button className="px-2 py-1.5 align-middle">
818
<svg

0 commit comments

Comments
 (0)