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
2 changes: 1 addition & 1 deletion commit/api/commit_project/commit_project.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ def get_project_list_with_branches():
"name", 'organization_name', 'github_org', 'image', 'about', 'creation'])
for organization in organizations:
projects = frappe.get_all("Commit Project", filters={
"org": organization.get("name")}, fields=["name", "display_name", "repo_name", "app_name", "image", "banner_image", "path_to_folder", 'description'], order_by="modified asc")
"org": organization.get("name")}, fields=["name", "display_name", "repo_name", "app_name", "image", "banner_image", "path_to_folder", 'description'], order_by="creation desc")
# organization["projects"] = projects
for project in projects:
branches = frappe.get_all("Commit Project Branch", filters={"project": project.get(
Expand Down
69 changes: 24 additions & 45 deletions dashboard/src/components/features/meta_apps/YourApps.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { FullPageLoader } from "@/components/common/FullPageLoader/FullPageLoader"
import { Avatar, AvatarFallback } from "@/components/ui/avatar"
import { Button } from "@/components/ui/button"
import { CardDescription } from "@/components/ui/card"
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
import { Card, CardContent, CardDescription, CardFooter, CardTitle } from "@/components/ui/card"
import { AvatarImage } from "@radix-ui/react-avatar"
import { useFrappeGetCall } from "frappe-react-sdk"
import { useMemo } from "react"
import { BsDatabase } from "react-icons/bs"
import { useNavigate } from "react-router-dom"
import { YourAppAPIExplorer } from "./YourAppAPIExplorer"
import { Badge } from "@/components/ui/badge"

export interface AppsData {
app_name: string
Expand Down Expand Up @@ -39,9 +39,8 @@ export const YourApps = () => {
if (data && data.message) {
return (
<div className="mx-auto px-4 h-[calc(100vh-4rem)]">
<div className="flex flex-row items-center space-x-2 gap-2 justify-between">
<h1 className="scroll-m-20 text-2xl font-semibold tracking-normal">
</h1>
<div className="flex flex-row items-center space-x-2 gap-2 justify-end">

<div className="flex items-center space-x-2">
<YourAppAPIExplorer />
<Button size='sm' onClick={() => {
Expand All @@ -53,58 +52,38 @@ export const YourApps = () => {
</Button>
</div>
</div>
<div className="h-full space-y-">
<ul role="list" className="divide-y divide-gray-200">
{data.message.map((app: AppsData) => {
return <ProjectCard key={app.app_name} app={app} />
})}
</ul>
<div className="flex gap-6 flex-wrap p-4">
{data.message.map((app: AppsData) => {
return <AppsCard key={app.app_name} app={app} />
})}
</div>
</div>
)
}
}


export const ProjectCard = ({ app }: { app: AppsData }) => {
const AppsCard = ({ app }: { app: AppsData }) => {

const appNameInitials = useMemo(() => {
return app.app_name.split('_').map((word) => word[0]).join('').toUpperCase()
}, [app])

return (
<li className="w-full h-auto hover:shadow-sm">
<div className="py-4 flex flex-col justify-between">
<div className="flex space-x-4 items-center justify-between">
<div className="flex space-x-3 items-center">
<Avatar className="h-11 w-11 rounded-md">
<AvatarImage src={app.app_logo_url} />
<AvatarFallback className="h-11 w-11 rounded-md">{appNameInitials}</AvatarFallback>
</Avatar>
<div className="flex flex-col">
<div className="flex space-x-2 items-center">
<h1 className="text-lg font-medium tracking-normal">{app.app_name}</h1>
<span className="text-sm text-gray-500">
by
</span>
<h1 className="text-md font-normal tracking-normal">{app.app_publisher}</h1>
</div>
<CardDescription className="text-sm text-gray-500">{app.app_description}</CardDescription>
</div>
</div>
<Select
disabled
defaultValue={app.git_branch}
>
<SelectTrigger className="h-8 w-40 truncate">
<SelectValue placeholder="Select Branch" />
</SelectTrigger>
<SelectContent>
<SelectItem value={app.git_branch ?? ''} key={app.git_branch} >{app.git_branch}</SelectItem>
</SelectContent>
</Select>
</div>
</div >
</li >
<Card className="w-[220px] h-[300px] relative">
<CardContent className="flex flex-col gap-4 items-start p-4">
<Avatar className="h-32 w-full flex items-center rounded-md border border-gray-100 justify-center">
<AvatarImage src={app.app_logo_url} />
<AvatarFallback className="rounded-md text-4xl">{appNameInitials}</AvatarFallback>
</Avatar>
<CardTitle>{app.app_name}</CardTitle>
<CardDescription>
{app.app_description}
</CardDescription>
</CardContent>
<CardFooter className="absolute mt-2 bottom-0 p-4">
<Badge variant="secondary">{app.app_publisher}</Badge>
</CardFooter>
</Card>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import { KeyedMutator } from "swr";
import { ProjectData } from "../Projects";
import DeleteOrgModal from "./DeleteOrgModal";
import { AlertDialog, AlertDialogTrigger } from "@/components/ui/alert-dialog";
import { ProjectCard } from "../Projects/ProjectsList";
import { ProjectCard } from "../Projects/ProjectCard";


interface OrgComponentProps {
org: ProjectData, mutate: KeyedMutator<{ message: ProjectData[]; }>
Expand All @@ -20,21 +21,21 @@ export const OrgComponent = ({ org, mutate }: OrgComponentProps) => {
{org.organization_name}
</h1>
{isCreateAccess && <AlertDialog>
<AlertDialogTrigger asChild>
<Button size="icon" variant="outline" className="h-7 w-7">
<AiOutlineDelete />
</Button>
</AlertDialogTrigger>
<DeleteOrgModal org={org} mutate={mutate} />
<AlertDialogTrigger asChild>
<Button size="icon" variant="outline" className="h-7 w-7">
<AiOutlineDelete />
</Button>
</AlertDialogTrigger>
<DeleteOrgModal org={org} mutate={mutate} />
</AlertDialog>}
</div>
<div className="pl-4">
{org.projects.map((project => {
{org.projects.map((project) => {
return (
<ProjectCard project={project} key={project.name} mutate={mutate} />
)
}
))}
)}
</div>
</div>
)
Expand Down
84 changes: 50 additions & 34 deletions dashboard/src/components/features/projects/Projects.tsx
Original file line number Diff line number Diff line change
@@ -1,42 +1,49 @@
import { FullPageLoader } from "@/components/common/FullPageLoader/FullPageLoader"
import { Button } from "@/components/ui/button"
import { Dialog, DialogTrigger } from "@/components/ui/dialog"
import { CommitProject } from "@/types/commit/CommitProject"
import { useFrappeGetCall } from "frappe-react-sdk"
import { BsDatabase } from "react-icons/bs"
import { ViewERDDialogContent } from "./ViewERDAppDialog"
import { isSystemManager } from "@/utils/roles"
import { CommitProjectBranch } from "@/types/commit/CommitProjectBranch"
import { OrgComponent } from "./Org/OrgList"
import { DropdownMenuDemo } from "./AddMenuButton"
import { APIExplorer } from "./APIExplorer"
import { FullPageLoader } from "@/components/common/FullPageLoader/FullPageLoader";
import { Button } from "@/components/ui/button";
import { Dialog, DialogTrigger } from "@/components/ui/dialog";
import { CommitProject } from "@/types/commit/CommitProject";
import { useFrappeGetCall } from "frappe-react-sdk";
import { BsDatabase } from "react-icons/bs";
import { ViewERDDialogContent } from "./ViewERDAppDialog";
import { isSystemManager } from "@/utils/roles";
import { CommitProjectBranch } from "@/types/commit/CommitProjectBranch";
import { DropdownMenuDemo } from "./AddMenuButton";
import { APIExplorer } from "./APIExplorer";
import ProjectCard from "./Projects/ProjectCard";


export interface ProjectWithBranch extends CommitProject {
branches: CommitProjectBranch[]
branches: CommitProjectBranch[];
}
export interface ProjectData extends CommitProjectBranch {
projects: ProjectWithBranch[]
organization_name: string
image: string
name: string
about: string
projects: ProjectWithBranch[];
organization_name: string;
image: string;
name: string;
about: string;
}
export const Projects = () => {
const isCreateAccess = isSystemManager();

const isCreateAccess = isSystemManager()

const { data, error, isLoading, mutate } = useFrappeGetCall<{ message: ProjectData[] }>('commit.api.commit_project.commit_project.get_project_list_with_branches', {}, 'get_project_list_with_branches', {
keepPreviousData: true,
revalidateOnFocus: true,
revalidateIfStale: false,
})
const { data, error, isLoading, mutate } = useFrappeGetCall<{
message: ProjectData[];
}>(
"commit.api.commit_project.commit_project.get_project_list_with_branches",
{},
"get_project_list_with_branches",
{
keepPreviousData: true,
revalidateOnFocus: true,
revalidateIfStale: false,
}
);

if (error) {
return <div>Error</div>
return <div>Error</div>;
}

if (isLoading) {
return <FullPageLoader />
return <FullPageLoader />;
}

if (data && data.message) {
Expand All @@ -48,20 +55,29 @@ export const Projects = () => {
<APIExplorer />
<Dialog>
<DialogTrigger asChild>
<Button size='sm' disabled={data.message.length === 0}>
<BsDatabase className='mr-2' /> View ERD
<Button size="sm" disabled={data.message.length === 0}>
<BsDatabase className="mr-2" /> View ERD
</Button>
</DialogTrigger>
<ViewERDDialogContent data={data.message} />
</Dialog>
</div>
<ul role="list" className="space-y-2 py-2">
<div className="flex gap-6 flex-wrap p-4">
{data.message.map((org: ProjectData) => {
return <OrgComponent org={org} key={org.organization_name} mutate={mutate} />
const orgName = org.organization_name;
return org.projects.map((project) => (
<ProjectCard
orgName={orgName}
project={project}
key={project.name}
mutate={mutate}
/>
));
})}
</ul>
</div>

</div>
</div>
)
);
}
}
};
104 changes: 104 additions & 0 deletions dashboard/src/components/features/projects/Projects/ProjectCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import { Button } from "@/components/ui/button";
import {
Card,
CardContent,
CardDescription,
CardFooter,
CardTitle,
} from "@/components/ui/card";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import { AiOutlineDelete } from "react-icons/ai";
import { AlertDialog } from "@/components/ui/alert-dialog";
import { KeyedMutator } from "swr";
import { useMemo, useState } from "react";
import { isSystemManager } from "@/utils/roles";
import { RxDragHandleDots1 } from "react-icons/rx";
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu";
import { BsThreeDotsVertical } from "react-icons/bs";
import { Dialog } from "@radix-ui/react-dialog";
import ManageBranchModal from "../Branch/ManageBranchModal";
import { ProjectWithBranch, ProjectData } from "../Projects";
import DeleteProjectModal from "./DeleteProjectModal";
import { Badge } from "@/components/ui/badge";

export interface ProjectCardProps {
project: ProjectWithBranch
mutate: KeyedMutator<{
message: ProjectData[];
}>
orgName: string
}

const ProjectCard = ({ project, mutate, orgName }: ProjectCardProps) => {

const appNameInitials = useMemo(() => {
return project.display_name[0].toUpperCase()
}, [project])

const isCreateAccess = isSystemManager()

const [openManageModal, setOpenManageModal] = useState(false)

const [openDeleteDialogModal, setOpenDeleteDialogModal] = useState(false)

return (
<Card className="w-[220px] h-[300px] relative">
<CardContent className="p-4">
<div className="flex flex-col gap-4 items-start">
<Avatar className="h-32 w-full flex items-center rounded-md border border-gray-100">
<AvatarImage src={project.image} />
<AvatarFallback className="rounded-md text-4xl">
{appNameInitials}
</AvatarFallback>
</Avatar>

<div className="flex flex-col gap-1 w-full">
<div className="flex justify-between items-center">
<CardTitle>{project.display_name}</CardTitle>
{isCreateAccess && <DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="outline" size='icon' className="h-8 w-8"> <BsThreeDotsVertical /></Button>
</DropdownMenuTrigger>
<DropdownMenuContent className="w-56">
{project.branches.length > 0 &&
<DropdownMenuItem onClick={() => { setOpenManageModal(true) }}>
<>
<RxDragHandleDots1 className="h-4 w-4 mr-1" />
<span> Manage Branches</span>
</>
</DropdownMenuItem>
}
<DropdownMenuItem onClick={() => setOpenDeleteDialogModal(true)}>
<AiOutlineDelete className="h-4 w-4 mr-1" />
<span>Delete Project</span>
</DropdownMenuItem>

</DropdownMenuContent>
</DropdownMenu>}
</div>

<CardDescription>
{project.description}
</CardDescription>
</div>


</div>
</CardContent>

<AlertDialog open={openDeleteDialogModal} onOpenChange={setOpenDeleteDialogModal}>
<DeleteProjectModal project={project} mutate={mutate} />
</AlertDialog>

<Dialog open={openManageModal} onOpenChange={setOpenManageModal}>
<ManageBranchModal branches={project.branches} mutate={mutate} setOpenManageModal={setOpenManageModal} />
</Dialog>

<CardFooter className="absolute p-4 bottom-0 mt-2">
<Badge variant="secondary">{orgName}</Badge>
</CardFooter>
</Card>
);
}

export default ProjectCard;
Loading