Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions core/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ pyjwt==2.10.1
requests==2.32.3
apache-airflow-client==2.3.0
networkx==2.8.8
Jinja2==3.1.5
2 changes: 1 addition & 1 deletion core/services/user_service/views/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
router = APIRouter(prefix="/user", tags=["user"])


@router.post("/create", response_model=CreateUserResponse)
@router.post("/", response_model=CreateUserResponse)
async def create_user(data: CreateUserRequest):
try:
userID = create_user_controller.create_user(data.email, data.password)
Expand Down
21 changes: 11 additions & 10 deletions core/services/workflow_service/views/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@
from uuid import UUID
from utils.errors.error import handle_error

import services.workflow_service.controllers.project_controller \
as project_controller

import services.workflow_service.controllers.project_controller as \
project_controller
from services.workflow_service.schemas.project import (
Project,
CreateProjectRequest,
Expand All @@ -13,15 +12,14 @@
ReadByUserResponse,
ReadAllResponse,
RenameProjectRequest,
DeleteProjectRequest,
AddNewBlockRequest
)


router = APIRouter(prefix="/project", tags=["project"])


@router.post("/create", response_model=CreateProjectResponse)
@router.post("/", response_model=CreateProjectResponse)
async def create_project(
data: CreateProjectRequest
):
Expand All @@ -35,7 +33,7 @@ async def create_project(
raise handle_error(e)


@router.get("/read", response_model=Project)
@router.get("/", response_model=Project)
async def read_project(data: ReadProjectRequest):
try:
project = project_controller.read_project(data.project_uuid)
Expand All @@ -61,7 +59,8 @@ async def read_all_projects():
raise handle_error(e)


@router.put("/rename", response_model=Project)
# TODO: Rename function aswell
@router.put("/", response_model=Project)
async def rename_project(data: RenameProjectRequest):
try:
updated_project = project_controller.rename_project(
Expand All @@ -72,10 +71,12 @@ async def rename_project(data: RenameProjectRequest):
raise handle_error(e)


@router.delete("/delete", status_code=200)
async def delete_project(data: DeleteProjectRequest):
@router.delete("/{project_id}", status_code=200)
async def delete_project(
project_id: UUID | None = None
):
try:
project_controller.delete_project(data.project_uuid)
project_controller.delete_project(project_id)
except Exception as e:
raise handle_error(e)

Expand Down
62 changes: 28 additions & 34 deletions frontend/app/dashboard/page.tsx
Original file line number Diff line number Diff line change
@@ -1,43 +1,37 @@
"use client"

import { useState } from "react"
import Button from "@/components/Button"
import { ReactFlowProvider } from "@xyflow/react"
import PageWithHeader from "@/components/layout/PageWithHeader"
import ProjectList from "@/components/ProjectList"
import useAuth from "@/hooks/useAuth"
import { useTestMutation } from "@/mutations/userMutation"
import type { Project } from "@/utils/types"
import { useAlert } from "@/hooks/useAlert"
import Workbench from "@/components/Workbench"
import LoadingAndError from "@/components/LoadingAndError"
import { SelectedProjectProvider } from "@/hooks/useSelectedProject"
import { SelectedComputeBlockProvider } from "@/hooks/useSelectedComputeBlock"

export default function Dashboard() {
const { setAlert } = useAlert()
const [selectedProject, setSelectedProject] = useState<Project | undefined>(undefined)
const { signOut, loading } = useAuth()
const { loading } = useAuth()

const { mutate } = useTestMutation(setAlert)

function test() {
mutate({ old_access_token: "abc", refresh_token: "acs" })
}

return !loading ? (
<PageWithHeader breadcrumbs={[{ text: "Dashboard", link: "/dashboard" }]}>
<div className="flex">
<div className="w-1/6 h-screen shadow-sm h-full">
<ProjectList selectedProject={selectedProject} setSelectedProject={setSelectedProject} />
</div>
<div>
Selected Project: {selectedProject?.name}
<Button onClick={(e) => {
e.preventDefault()
signOut()
}}>SignOut</Button>
<Button onClick={(e) => {
e.preventDefault()
test()
}}>Test</Button>
</div>
</div>
</PageWithHeader>
) : (<></>)
return (
<LoadingAndError loading={loading}>
<SelectedProjectProvider>
<SelectedComputeBlockProvider>
<PageWithHeader breadcrumbs={[{ text: "Dashboard", link: "/dashboard" }]}>
<div className="flex h-full">
{/* ProjectList is scrollable and takes 1/4 width */}
<div className="w-1/4 h-full overflow-y-auto shadow">
<ProjectList />
</div>
{/* Workbench takes the rest of the space */}
<div className="flex-grow h-full">
<ReactFlowProvider>
<Workbench />
</ReactFlowProvider>
</div>
</div>
</PageWithHeader>
</SelectedComputeBlockProvider>
</SelectedProjectProvider>
</LoadingAndError>
)
}
2 changes: 1 addition & 1 deletion frontend/components/Alert.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export default function Alert() {

if (text) {
return (
<div className={`${alertColor} text-white p-4 rounded-md fixed bottom-5 left-1/2 transform -translate-x-1/2 -translate-y-1/2 flex justify-between items-center`}>
<div className={`${alertColor} z-50 text-white p-4 rounded-md fixed bottom-5 left-1/2 transform -translate-x-1/2 -translate-y-1/2 flex justify-between items-center`}>
{text}
</div>
)
Expand Down
58 changes: 58 additions & 0 deletions frontend/components/CreateComputeBlockModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { useState } from "react"
import LoadingAndError from "./LoadingAndError"
import Modal, { type ModalProps } from "./Modal"
import Input from "./inputs/Input"

type CreateComputeBlockModalProps = Omit<ModalProps, "children">;

export default function CreateComputeBlockModal({
isOpen,
onClose,
className = "",
}: CreateComputeBlockModalProps) {
const [cbName, setCBName] = useState<string>("")
const [repoURL, setRepoURL] = useState<string>("")

// TODO: Api Call

return (
<Modal className={className} isOpen={isOpen} onClose={onClose}>
<h2 className="text-xl font-bold">Create Compute Block:</h2>
<form onSubmit={() => { }} className="mt-4 space-y-4 text-sm">
<div>
<Input
type="text"
value={cbName}
label="Compute Block Title"
onChange={setCBName}
/>
<Input
type="text"
value={repoURL}
label="Repository URL"
onChange={setRepoURL}
/>
</div>
<div className="flex justify-end">
<button
type="button"
onClick={onClose}
className="w-[78px] h-[36px] px-4 py-2 mr-2 text-gray-700 bg-gray-100 rounded hover:bg-gray-200"
>
Cancel
</button>
<button
type="submit"
className="flex flex-col w-[78px] h-[36px] px-4 py-2 text-white bg-blue-500 rounded hover:bg-blue-600"
disabled={false}
>
<LoadingAndError loading={false} iconSize={21}>
Create
</LoadingAndError>
</button>
</div>
</form>
</Modal >

)
}
66 changes: 66 additions & 0 deletions frontend/components/CreateProjectModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { useState } from "react"
import Input from "./inputs/Input"
import Modal, { type ModalProps } from "./Modal"
import LoadingAndError from "./LoadingAndError"
import { useCreateProjectMutation } from "@/mutations/projectMutation"
import { AlertType, useAlert } from "@/hooks/useAlert"

type CreateProjectModalProps = Omit<ModalProps, "children">;

export default function CreateProjectModal({
isOpen,
onClose,
className = "",
}: CreateProjectModalProps) {
const { setAlert } = useAlert()
const [projectName, setProjectName] = useState<string>("")

const { mutate, isPending: loading } = useCreateProjectMutation(setAlert)

function createProject(e: React.FormEvent<HTMLFormElement>) {
e.preventDefault()

// TODO: Currently this validation is fine, as we are only using one field.
// However, think about a better way to validate the fields
if (projectName.length > 0) {
mutate({ name: projectName })
onClose()
} else {
setAlert("Project Name must be set.", AlertType.ERROR)
}
}

return (
<Modal isOpen={isOpen} onClose={onClose} className={className}>
<h2 className="text-xl font-bold">Project</h2>
<form onSubmit={(e) => createProject(e)} className="mt-4 space-y-4 text-sm">
<div>
<Input
type="text"
value={projectName}
label="Project Name"
onChange={setProjectName}
/>
</div>
<div className="flex justify-end">
<button
type="button"
onClick={onClose}
className="w-[78px] h-[36px] px-4 py-2 mr-2 text-gray-700 bg-gray-100 rounded hover:bg-gray-200"
>
Cancel
</button>
<button
type="submit"
className="flex flex-col w-[78px] h-[36px] px-4 py-2 text-white bg-blue-500 rounded hover:bg-blue-600"
disabled={loading}
>
<LoadingAndError loading={loading} iconSize={21}>
Create
</LoadingAndError>
</button>
</div>
</form>
</Modal>
)
}
53 changes: 53 additions & 0 deletions frontend/components/DeleteProjectModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import LoadingAndError from "./LoadingAndError"
import Modal, { type ModalProps } from "./Modal"
import { useDeleteProjectMutation } from "@/mutations/projectMutation"
import { useAlert } from "@/hooks/useAlert"
import { useSelectedProject } from "@/hooks/useSelectedProject"

type DeleteProjectModalProps = Omit<ModalProps, "children">;

export default function DeleteProjectModal({
isOpen,
onClose,
className = "",
}: DeleteProjectModalProps) {
const { setAlert } = useAlert()
const { selectedProject, setSelectedProject } = useSelectedProject()

const { mutate: deleteMutate, isPending: deleteLoading } = useDeleteProjectMutation(setAlert)

function onDelete() {
if (selectedProject) {
deleteMutate(selectedProject.uuid)
onClose()
setSelectedProject(undefined)
}
}

return (
<Modal className={className} isOpen={isOpen} onClose={onClose}>
<h2 className="text-xl font-bold">Delete Project</h2>
Are you sure that you want to delete the project: <span className="text-blue-600"><b>{selectedProject?.name}</b></span>
<div className="flex justify-end mt-5">
<button
type="button"
onClick={onClose}
className="w-[78px] h-[36px] px-4 py-2 mr-2 text-gray-700 bg-gray-100 rounded hover:bg-gray-200"
>
Cancel
</button>
<button
className="flex flex-col w-[78px] h-[36px] px-4 py-2 text-white bg-red-500 rounded hover:bg-red-600"
disabled={deleteLoading}
onClick={() => onDelete()}
>
<LoadingAndError loading={deleteLoading} iconSize={21}>
Delete
</LoadingAndError>
</button>
</div>

</Modal>

)
}
Loading
Loading