diff --git a/commit/commit/doctype/commit_project_branch/commit_project_branch.py b/commit/commit/doctype/commit_project_branch/commit_project_branch.py index d78db59..3b92539 100644 --- a/commit/commit/doctype/commit_project_branch/commit_project_branch.py +++ b/commit/commit/doctype/commit_project_branch/commit_project_branch.py @@ -10,6 +10,7 @@ from commit.commit.code_analysis.apis import find_all_occurrences_of_whitelist from commit.commit.code_analysis.doctypes import get_doctypes_in_module, get_doctype_json from frappe.utils import now +from frappe.app import handle_exception class CommitProjectBranch(Document): @@ -46,8 +47,7 @@ def clone_repo(self): # print("Folder path", folder_path) # print("Repo url", repo_url) # print("Branch name", self.branch_name) - repo = git.Repo.clone_from( - repo_url, folder_path, branch=self.branch_name, single_branch=True) + repo = git.Repo.clone_from(repo_url, folder_path, branch=self.branch_name, single_branch=True) # print("Cloned repo") self.last_fetched = frappe.utils.now_datetime() self.commit_hash = repo.head.object.hexsha @@ -158,18 +158,36 @@ def background_fetch_process(project_branch): 'is_completed': True }, user=frappe.session.user) - - - except frappe.DoesNotExistError: + except Exception as e: # throw the error and delete the document - frappe.throw("Project Branch not found") + messages = [json.dumps({'message' :'There was an error while fetching branch repo.'})] + frappe.clear_messages() + frappe.publish_realtime('commit_branch_creation_error', + { + 'branch_name': doc.branch_name, + 'project': doc.project, + 'error':{ + "exception": frappe.get_traceback(), + "_server_messages": json.dumps(messages), + }, + # 'response': handle_exception(e), + 'is_completed': False + }, user=frappe.session.user) + frappe.delete_doc("Commit Project Branch", project_branch) + # frappe.throw("Project Branch not found") + frappe.log(frappe.get_traceback()) + + # raise e @frappe.whitelist(allow_guest=True) -def fetch_repo(doc): - doc = json.loads(doc) - project_branch = frappe.get_doc("Commit Project Branch", doc.get("name")) +def fetch_repo(doc, name = None): + if name : + project_branch = frappe.get_doc("Commit Project Branch", name) + else: + doc = json.loads(doc) + project_branch = frappe.get_doc("Commit Project Branch", doc.get("name")) project_branch.fetch_repo() project_branch.save() return "Hello" diff --git a/commit/public/dashboard/index.html b/commit/public/dashboard/index.html index 3ff2ee4..98685a3 100644 --- a/commit/public/dashboard/index.html +++ b/commit/public/dashboard/index.html @@ -12,13 +12,17 @@ Commit - Developer tooling for the Frappeverse - - + +
+ diff --git a/commit/www/dashboard.html b/commit/www/dashboard.html index 3ff2ee4..98685a3 100644 --- a/commit/www/dashboard.html +++ b/commit/www/dashboard.html @@ -12,13 +12,17 @@ Commit - Developer tooling for the Frappeverse - - + +
+ diff --git a/dashboard/src/components/features/projects/Branch/CreateBranchModal.tsx b/dashboard/src/components/features/projects/Branch/CreateBranchModal.tsx index 2b212c8..f7792f8 100644 --- a/dashboard/src/components/features/projects/Branch/CreateBranchModal.tsx +++ b/dashboard/src/components/features/projects/Branch/CreateBranchModal.tsx @@ -66,9 +66,22 @@ const CreateBranchModal = ({ project, mutate, setBranch, setOpen }: BranchProps) } }) + useFrappeEventListener('commit_branch_creation_error', (data) => { + if (data.branch_name === branchName && data.project === project.name) { + setDesc("") + setCreationError(data.error) + setEventLoading(false) + setBranch("") + } + }) + + const [creationError, setCreationError] = useState(null) + + const handleClose = (name: string, branch_name: string) => { setEventLoading(false) setBranch(name) + setCreationError(null) methods.reset() toast({ description: `Branch ${branch_name} added for ${project.app_name}` @@ -99,6 +112,7 @@ const CreateBranchModal = ({ project, mutate, setBranch, setOpen }: BranchProps) {error && } + {creationError && }
@@ -110,11 +124,13 @@ const CreateBranchModal = ({ project, mutate, setBranch, setOpen }: BranchProps) className="mb-3 p-3 w-full" /> -
diff --git a/dashboard/src/components/features/projects/Branch/ManageBranchItem.tsx b/dashboard/src/components/features/projects/Branch/ManageBranchItem.tsx new file mode 100644 index 0000000..8ad272a --- /dev/null +++ b/dashboard/src/components/features/projects/Branch/ManageBranchItem.tsx @@ -0,0 +1,69 @@ +import { Button } from '@/components/ui/button' +import { toast } from '@/components/ui/use-toast' +import { convertFrappeTimestampToTimeAgo } from '@/components/utils/dateconversion' +import { CommitProjectBranch } from '@/types/commit/CommitProjectBranch' +import { useFrappeDeleteDoc, useFrappePostCall } from 'frappe-react-sdk' +import { AiOutlineDelete } from 'react-icons/ai' +import { IoMdSync } from 'react-icons/io' +import { ProjectData } from '../Projects' +import { KeyedMutator } from 'swr' + + +const ManageBranchItem = ({ branch, mutate }: { branch: CommitProjectBranch, mutate: KeyedMutator<{ message: ProjectData[]; }> }) => { + const { call, loading, reset: callReset } = useFrappePostCall<{ message: any }>('commit.commit.doctype.commit_project_branch.commit_project_branch.fetch_repo') + + + const { deleteDoc, reset, loading: deleteLoading } = useFrappeDeleteDoc() + + const handleDelete = () => { + deleteDoc("Commit Project Branch", branch.name) + .then(() => { + mutate() + reset() + }).then(() => toast({ + description: "Branch Deleted Successfully", + })) + } + + const handleSync = () => { + call({ + doc: {}, + name: branch.name, + }).then(() => { + mutate() + callReset() + }).then(() => toast({ + description: "Branch Synced!", + })) + } + + return ( +
  • +
    + {branch.branch_name} +
    + Last synced {convertFrappeTimestampToTimeAgo(branch.last_fetched)} +
    +
    +
    + + +
    +
  • + ) +} + +export default ManageBranchItem \ No newline at end of file diff --git a/dashboard/src/components/features/projects/Branch/ManageBranchModal.tsx b/dashboard/src/components/features/projects/Branch/ManageBranchModal.tsx new file mode 100644 index 0000000..625dcd7 --- /dev/null +++ b/dashboard/src/components/features/projects/Branch/ManageBranchModal.tsx @@ -0,0 +1,43 @@ +import { DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog" +import { ProjectData } from "../Projects" +import { Button } from "@/components/ui/button" +import { KeyedMutator } from "swr" +import { CommitProjectBranch } from "@/types/commit/CommitProjectBranch" +import ManageBranchItem from "./ManageBranchItem" + +export interface ManageBranchModalProps { + branches: CommitProjectBranch[] + mutate: KeyedMutator<{ message: ProjectData[]; }> + setOpenManageModal: React.Dispatch> +} + + +const ManageBranchModal = ({ branches, mutate, setOpenManageModal }: ManageBranchModalProps) => { + + return ( + + + Manage Branches + + Update or Delete Branches + + +
      + {branches?.map((branch: CommitProjectBranch) => { + return ( + + ) + } + )} +
    + + + +
    + ) +} + + +export default ManageBranchModal \ No newline at end of file diff --git a/dashboard/src/components/features/projects/Org/CreateOrgModal.tsx b/dashboard/src/components/features/projects/Org/CreateOrgModal.tsx index beeeee6..d986e70 100644 --- a/dashboard/src/components/features/projects/Org/CreateOrgModal.tsx +++ b/dashboard/src/components/features/projects/Org/CreateOrgModal.tsx @@ -14,12 +14,12 @@ type FormFields = { about: string, } +interface CreateOrgModalProps { + mutate: KeyedMutator<{ message: ProjectData[]; }> +} + -const CreateOrgModal = ({ mutate }: { - mutate: KeyedMutator<{ - message: ProjectData[]; - }> -}) => { +const CreateOrgModal = ({ mutate }: CreateOrgModalProps) => { const { toast } = useToast() const methods = useForm() @@ -71,7 +71,7 @@ const CreateOrgModal = ({ mutate }: { className="mb-3 p-3 w-full" /> - diff --git a/dashboard/src/components/features/projects/Org/DeleteOrgModal.tsx b/dashboard/src/components/features/projects/Org/DeleteOrgModal.tsx index 4caebea..9401027 100644 --- a/dashboard/src/components/features/projects/Org/DeleteOrgModal.tsx +++ b/dashboard/src/components/features/projects/Org/DeleteOrgModal.tsx @@ -1,15 +1,17 @@ -import { AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger } from '@/components/ui/alert-dialog' +import { AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle } from '@/components/ui/alert-dialog' import { Button } from '@/components/ui/button' import { ProjectData } from '../Projects' import { useFrappeDeleteDoc } from 'frappe-react-sdk' import { toast } from '@/components/ui/use-toast' import { KeyedMutator } from 'swr' -const DeleteOrgModal = ({ org, mutate }: { - org: ProjectData, mutate: KeyedMutator<{ - message: ProjectData[]; - }> -}) => { +interface DeleteOrgModalProps { + org: ProjectData, + mutate: KeyedMutator<{ message: ProjectData[]; }> +} + + +const DeleteOrgModal = ({ org, mutate }: DeleteOrgModalProps) => { const { deleteDoc, reset } = useFrappeDeleteDoc() @@ -21,7 +23,6 @@ const DeleteOrgModal = ({ org, mutate }: { reset() }).then(() => toast({ description: `Organization ${org.organization_name} Deleted`, - variant: "destructive" })) } return ( @@ -36,7 +37,7 @@ const DeleteOrgModal = ({ org, mutate }: { Cancel diff --git a/dashboard/src/components/features/projects/Projects.tsx b/dashboard/src/components/features/projects/Projects.tsx index c8309d7..7dda410 100644 --- a/dashboard/src/components/features/projects/Projects.tsx +++ b/dashboard/src/components/features/projects/Projects.tsx @@ -2,10 +2,9 @@ import { FullPageLoader } from "@/components/common/FullPageLoader.tsx/FullPageL import { Avatar, AvatarFallback } from "@/components/ui/avatar" import { Button } from "@/components/ui/button" import { CardDescription } from "@/components/ui/card" -import { Dialog, DialogContent, DialogTrigger } from "@/components/ui/dialog" +import { Dialog, DialogTrigger } from "@/components/ui/dialog" import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select" import { CommitProject } from "@/types/commit/CommitProject" -import { CommitProjectBranch } from "@/types/commit/CommitProjectBranch" import { AvatarImage } from "@radix-ui/react-avatar" import { useFrappeGetCall } from "frappe-react-sdk" import { useMemo, useState } from "react" @@ -23,6 +22,9 @@ import { AiOutlineDelete } from "react-icons/ai"; import DeleteOrgModal from "./Org/DeleteOrgModal" import { AlertDialog, AlertDialogTrigger } from "@/components/ui/alert-dialog" import { RxDragHandleDots1 } from "react-icons/rx"; +import ManageBranchModal from "./Branch/ManageBranchModal" +import { CommitProjectBranch } from "@/types/commit/CommitProjectBranch" +import DeleteProjectModal from "./Projects/DeleteProjectModal" export interface ProjectWithBranch extends CommitProject { branches: CommitProjectBranch[] @@ -48,6 +50,8 @@ export const Projects = () => { return } + // const [createOrg, setCreateOrg] = useState(false) + if (data && data.message) { return ( @@ -67,12 +71,12 @@ export const Projects = () => { {isCreateAccess && - - - + + + } @@ -89,16 +93,20 @@ export const Projects = () => { } -export const OrgComponent = ({ org, mutate }: { - org: ProjectData, mutate: KeyedMutator<{ - message: ProjectData[]; - }> -}) => { +interface OrgComponentProps { + org: ProjectData, mutate: KeyedMutator<{ message: ProjectData[]; }> +} + +export const OrgComponent = ({ org, mutate }: OrgComponentProps) => { const isCreateAccess = isSystemManager() const [createProject, setCreateProject] = useState(false) + const handleClose = () => { + setCreateProject(false) + } + return (
    @@ -108,26 +116,24 @@ export const OrgComponent = ({ org, mutate }: { {isCreateAccess &&
    - - - - - - + -
    } + + +
    - {org?.projects?.length === 0 &&
    No Projects Found, Click to add a new project.
    }
    @@ -169,6 +175,8 @@ export const ProjectCard = ({ project, org, mutate }: ProjectCardProps) => { const [open, setOpen] = useState(false) + const [openManageModal, setOpenManageModal] = useState(false) + const [selectOpen, setSelectOpen] = useState(false) return ( @@ -200,6 +208,7 @@ export const ProjectCard = ({ project, org, mutate }: ProjectCardProps) => { open={selectOpen} onOpenChange={setSelectOpen} onValueChange={(value) => setBranch(value)} + value={branch} defaultValue={project.branches[0]?.name} > setSelectOpen(!selectOpen)}> @@ -211,39 +220,62 @@ export const ProjectCard = ({ project, org, mutate }: ProjectCardProps) => { {branch.branch_name} ) })} - { - project.branches.length > 0 && isCreateAccess && -
    } + {isCreateAccess && + <> + { + project.branches.length > 0 && +
    } } + + Add Branch + - {isCreateAccess && - - - - - Manage Branch Modal.. - - } + } + + } + + + + + + + + +
    + + + + + + +
    +
    diff --git a/dashboard/src/components/features/projects/Projects/CreateProjectModal.tsx b/dashboard/src/components/features/projects/Projects/CreateProjectModal.tsx index 82c292e..01a81ec 100644 --- a/dashboard/src/components/features/projects/Projects/CreateProjectModal.tsx +++ b/dashboard/src/components/features/projects/Projects/CreateProjectModal.tsx @@ -12,14 +12,15 @@ export type FormFields = { org: string, repo_name: string, display_name: string, + description: string, +} +interface CreateProjectModalProps { + org: ProjectData, + mutate: KeyedMutator<{ message: ProjectData[]; }>, + onClose: VoidFunction } - -const CreateProjectModal = ({ org, mutate }: { - org: ProjectData, mutate: KeyedMutator<{ - message: ProjectData[]; - }> -}) => { +const CreateProjectModal = ({ org, mutate, onClose }: CreateProjectModalProps) => { const { toast } = useToast() const methods = useForm({ defaultValues: { @@ -34,7 +35,8 @@ const CreateProjectModal = ({ org, mutate }: { .then(() => { reset() }).then(() => { - mutate(); + mutate() + onClose() return toast({ description: "Project Added", }) @@ -69,6 +71,14 @@ const CreateProjectModal = ({ org, mutate }: { placeholder="eg. lms" className="mb-3 p-3 w-full" /> + + + + + ) +} + +export default DeleteProjectModal \ No newline at end of file diff --git a/dashboard/src/components/features/projects/ViewERDAppDialog.tsx b/dashboard/src/components/features/projects/ViewERDAppDialog.tsx index 7d3f46a..d98b5e9 100644 --- a/dashboard/src/components/features/projects/ViewERDAppDialog.tsx +++ b/dashboard/src/components/features/projects/ViewERDAppDialog.tsx @@ -32,7 +32,7 @@ export const ViewERDDialogContent = ({ data }: { data: ProjectData[] }) => {
      {data?.map((org: ProjectData) => { - return org.projects.map((project => { + return org.projects?.filter((project) => project.branches?.length > 0)?.map((project => { return ( ) @@ -62,7 +62,7 @@ export const ViewERDProjectCard = ({ project, apps, setApps }: ViewERDProjectCar }, [project]) return (
    • -
      +
      { + + if (timestamp) { + const date = convertFrappeTimestampToUserTimezone(timestamp) + + return date.fromNow(withoutSuffix) + } + return '' +} + +export const convertFrappeTimestampToUserTimezone = (timestamp: string): Moment => { + // @ts-ignore + const systemTimezone = window.frappe?.boot?.time_zone?.system + // @ts-ignore + const userTimezone = window.frappe?.boot?.time_zone?.user + + if (systemTimezone && userTimezone) { + return moment.tz(timestamp, systemTimezone).clone().tz(userTimezone) + } else { + return moment(timestamp) + } +} \ No newline at end of file