diff --git a/apps/web/src/components/projects/projects-page.tsx b/apps/web/src/components/projects/projects-page.tsx new file mode 100644 index 0000000..56accd7 --- /dev/null +++ b/apps/web/src/components/projects/projects-page.tsx @@ -0,0 +1,465 @@ +import { authClient } from "@code/auth/web"; +import { api } from "@code/backend/convex/_generated/api"; +import type { Id } from "@code/backend/convex/_generated/dataModel"; +import { Button } from "@code/ui/components/button"; +import { useAction, useMutation, useQuery } from "convex/react"; +import { makeFunctionReference } from "convex/server"; +import { + FileText, + FolderGit2, + GitBranch, + LoaderCircle, + Server, +} from "lucide-react"; +import { useEffect, useState } from "react"; +import { Link, useNavigate, useSearchParams } from "react-router"; + +const connectGithubRef = makeFunctionReference< + "action", + Record, + { connectionId: Id<"gitConnections"> } +>("gitConnections:connectGithub"); +const connectGiteaRef = makeFunctionReference< + "action", + { token: string; username?: string }, + { connectionId: Id<"gitConnections"> } +>("gitConnections:connectGitea"); +const createProjectFromRepositoryRef = makeFunctionReference< + "mutation", + { gitRepositoryId: Id<"gitRepositories">; name: string }, + { projectId: Id<"projects"> } +>("gitProvisioning:createProjectFromRepository"); + +const LoadingState = () => ( +
+ +
+); + +const EmptyProjects = () => ( +
+ + + +

+ Connect your first project +

+

+ Choose a Git provider below to get started. +

+
+); + +const ProjectCard = ({ + instructions, + name, + projectId, + sourceUrl, +}: { + instructions: string; + name: string; + projectId: string; + sourceUrl: string; +}) => ( + +
+ +

{name}

+
+

{sourceUrl}

+ {instructions ? ( +
+ + Context configured +
+ ) : null} + +); + +const ContextEditor = ({ + projectId, +}: { + readonly projectId: Id<"projects">; +}) => { + const instructions = useQuery(api.projects.getInstructions, { + projectId, + }); + const updateInstructions = useMutation(api.projects.updateInstructions); + const [draft, setDraft] = useState(); + const [saving, setSaving] = useState(false); + + const currentDraft = draft ?? instructions ?? ""; + const dirty = draft !== undefined && draft !== (instructions ?? ""); + + const save = async () => { + if (!dirty || saving) { + return; + } + setSaving(true); + try { + await updateInstructions({ + instructions: draft ?? "", + projectId, + }); + setDraft(undefined); + } finally { + setSaving(false); + } + }; + + return ( +
+ +