Skip to content

Commit

Permalink
feature/ updates to create project form and testing github
Browse files Browse the repository at this point in the history
  • Loading branch information
psiddharthdesign committed Jul 22, 2024
1 parent f87caaa commit d7b2e13
Show file tree
Hide file tree
Showing 8 changed files with 702 additions and 306 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import moment from 'moment';
import Link from 'next/link';
import { useEffect, useState } from 'react';

type ProjectWithRepo = Tables<'projects'> & { repoName: string | null };
type ProjectWithRepo = Tables<'projects'> & { repoFullName: string | null };

type Props = {
projects: Tables<'projects'>[];
Expand All @@ -40,7 +40,7 @@ export function OrganizationProjectsTable({ projects }: Props) {
const updatedProjects = await Promise.all(
projects.map(async (project) => {
const repoDetails = await getRepoDetails(project.repo_id);
return { ...project, repoName: repoDetails?.name ?? null };
return { ...project, repoFullName: repoDetails?.repo_full_name ?? null };
})
);
setProjectsWithRepos(updatedProjects);
Expand Down Expand Up @@ -79,8 +79,8 @@ export function OrganizationProjectsTable({ projects }: Props) {
<div className="flex items-center bg-muted/50 p-1 rounded-md border w-fit px-2">
<GitBranch className="mr-1 h-4 w-4" />
<span>
{row.original.repoName ? `${row.original.repoName.toLowerCase().replace(/\s+/g, '-').replace(/[A-Z]/g, (letter) => letter.toLowerCase())}` : ''}
{row.original.repoName && ((row.getValue('terraform_working_dir') as string) || '') ? '/' : ''}
{row.original.repoFullName ? `${row.original.repoFullName.toLowerCase().replace(/\s+/g, '-').replace(/[A-Z]/g, (letter) => letter.toLowerCase())}` : ''}
{row.original.repoFullName && ((row.getValue('terraform_working_dir') as string) || '') ? '/' : ''}
{((row.getValue('terraform_working_dir') as string) || '').replace(/\s+/g, '-').replace(/[A-Z]/g, (letter) => letter.toLowerCase())}
</span>
</div>
Expand Down
185 changes: 100 additions & 85 deletions src/components/CreateProjectForm.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
'use client'

import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import { Checkbox } from "@/components/ui/checkbox";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { ScrollArea, ScrollBar } from "@/components/ui/scroll-area";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { createProjectAction } from "@/data/user/projects";
import { useSAToastMutation } from "@/hooks/useSAToastMutation";
import { generateSlug } from "@/lib/utils";
import { zodResolver } from "@hookform/resolvers/zod";
import { GitHubLogoIcon } from "@radix-ui/react-icons";
import { motion } from "framer-motion";
import { Check, Github } from "lucide-react";
import { AlertCircle, Github } from "lucide-react";
import Link from "next/link";
import { useRouter } from "next/navigation";
import { useState } from 'react';
import { FormEvent, useState } from 'react';
import { Controller, useForm } from "react-hook-form";
import { z } from "zod";
import { InputTags } from "./InputTags";
Expand All @@ -24,17 +24,16 @@ const MotionCard = motion(Card);

const createProjectFormSchema = z.object({
name: z.string().min(1, "Project name is required"),
repository: z.number().int().positive("Repository ID must be a positive integer"),
repository: z.number().int().positive("Please select a repository"),
terraformDir: z.string().min(1, "Terraform working directory is required"),
managedState: z.boolean(),
labels: z.array(z.string()),
});

type CreateProjectFormData = z.infer<typeof createProjectFormSchema>;

type Repository = {
id: number;
name: string;
repo_full_name: string | null;
};

type CreateProjectFormProps = {
Expand All @@ -43,16 +42,14 @@ type CreateProjectFormProps = {
};

export default function CreateProjectForm({ organizationId, repositories }: CreateProjectFormProps) {
const [selectedRepo, setSelectedRepo] = useState(repositories[0]?.id || null);
const router = useRouter();

const { control, handleSubmit, setValue, watch } = useForm<CreateProjectFormData>({
const { control, handleSubmit, formState: { errors } } = useForm<CreateProjectFormData>({
resolver: zodResolver(createProjectFormSchema),
defaultValues: {
name: "",
repository: repositories[0]?.id || 0,
terraformDir: "",
managedState: true,
labels: [],
},
});
Expand All @@ -66,7 +63,6 @@ export default function CreateProjectForm({ organizationId, repositories }: Crea
slug,
repoId: data.repository,
terraformWorkingDir: data.terraformDir,
isManagingState: data.managedState,
labels: data.labels,
});
},
Expand All @@ -80,34 +76,30 @@ export default function CreateProjectForm({ organizationId, repositories }: Crea
}
},
},
);
)


// isSubmitting is used to disable the submit button while the form is being submitted
const [isSubmitting, setIsSubmitting] = useState(false);

const onSubmit = (data: CreateProjectFormData) => {
setIsSubmitting(true);
createProjectMutation.mutate(data);
};

const handleFormSubmit = (e: FormEvent) => {
e.preventDefault();
handleSubmit(onSubmit)();
};

return (
<div className="p-6 max-w-4xl mx-auto">
<form onSubmit={(e) => {
e.preventDefault();
handleSubmit(onSubmit)(e);
}}>
{/* {Object.entries(watch()).map(([key, value]) => (
<div key={key}>
<strong>{key}:</strong> {JSON.stringify(value)}
</div>
))} */}
<div className="mb-6 flex justify-between items-center">
<form onSubmit={handleFormSubmit}>
<div className="mb-6 flex justify-start items-center">
<div>
<T.H3>Create new Project</T.H3>
<T.P className="text-muted-foreground">Create a new project within your organization.</T.P>
</div>
<div className="flex space-x-2 mt-6">
<Button type="button" variant="outline" onClick={() => router.back()}>Cancel</Button>
<Button type="submit" disabled={createProjectMutation.isLoading}>
{createProjectMutation.isLoading ? "Creating..." : "Create Project"}
</Button>
</div>
</div>

<MotionCard
Expand All @@ -129,12 +121,20 @@ export default function CreateProjectForm({ organizationId, repositories }: Crea
name="name"
control={control}
render={({ field }) => (
<Input
id="name"
placeholder="Enter workspace name"
className="mt-1"
{...field}
/>
<div className="relative">
<Input
id="name"
placeholder="Enter project name"
className={`mt-1 ${errors.name ? 'border-destructive' : ''}`}
{...field}
/>
{errors.name && (
<div className="flex items-center mt-1 text-destructive">
<AlertCircle className="h-4 w-4 mr-1" />
<span className="text-sm">{errors.name.message}</span>
</div>
)}
</div>
)}
/>
</div>
Expand All @@ -152,39 +152,54 @@ export default function CreateProjectForm({ organizationId, repositories }: Crea
<CardTitle className="text-lg">Select a repository</CardTitle>
<CardDescription className="text-sm text-muted-foreground">Choose the repository for your project</CardDescription>
</div>
<Badge variant="outline" size="lg" className="flex py-1.5 items-center space-x-1">
<Github className="h-4 w-4 mr-1" />
<span>Connected to GitHub</span>
<Check className="h-3 w-3 ml-1" />
</Badge>

<Link
href="https://github.com/apps/digger-cloud-next/installations/select_target"
onClick={(e) => e.stopPropagation()}
>
<Button
type="button"
variant='secondary'
size='sm'
className="gap-1"
onClick={(e) => e.stopPropagation()}
>
<GitHubLogoIcon className="h-4 w-4 mr-1" />
Configure Github
</Button>
</Link>
</CardHeader>
<CardContent>
{repositories.length > 0 ? (
<ScrollArea className="w-full whitespace-nowrap rounded-md border">
<div className="flex w-max space-x-4 p-4">
{repositories.map((repo, index) => (
<MotionCard
key={repo.id}
className={`w-[200px] cursor-pointer ${selectedRepo === repo.id ? 'ring-2 ring-primary' : ''}`}
whileHover={{ scale: 1.05 }}
whileTap={{ scale: 0.95 }}
onClick={() => {
setSelectedRepo(repo.id);
setValue("repository", repo.id);
}}
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: index * 0.1 }}
>
<CardContent className="flex items-center justify-center p-6">
<Github className="mr-2 h-6 w-6" />
<span>{repo.name}</span>
</CardContent>
</MotionCard>
))}
</div>
<ScrollBar orientation="horizontal" />
</ScrollArea>
<Controller
name="repository"
control={control}
render={({ field }) => (
<div className="relative">
<Select onValueChange={(value) => field.onChange(parseInt(value))} value={field.value.toString()}>
<SelectTrigger className={`w-full ${errors.repository ? 'border-destructive' : ''}`}>
<SelectValue placeholder="Select a repository" />
</SelectTrigger>
<SelectContent>
{repositories.map((repo) => (
<SelectItem key={repo.id} value={repo.id.toString()}>
<div className="flex items-center">
<Github className="mr-2 h-4 w-4" />
<span>{repo.repo_full_name}</span>
</div>
</SelectItem>
))}
</SelectContent>
</Select>
{errors.repository && (
<div className="flex items-center mt-1 text-destructive">
<AlertCircle className="h-4 w-4 mr-1" />
<span className="text-sm">{errors.repository.message}</span>
</div>
)}
</div>
)}
/>
) : (
<div className="text-center py-8">
<div className="bg-muted/50 rounded-full p-4 inline-block">
Expand Down Expand Up @@ -218,12 +233,20 @@ export default function CreateProjectForm({ organizationId, repositories }: Crea
name="terraformDir"
control={control}
render={({ field }) => (
<Input
id="terraformDir"
placeholder="Enter directory path"
className="mt-1"
{...field}
/>
<div className="relative">
<Input
id="terraformDir"
placeholder="Enter directory path"
className={`mt-1 ${errors.terraformDir ? 'border-destructive' : ''}`}
{...field}
/>
{errors.terraformDir && (
<div className="flex items-center mt-1 text-destructive">
<AlertCircle className="h-4 w-4 mr-1" />
<span className="text-sm">{errors.terraformDir.message}</span>
</div>
)}
</div>
)}
/>
</div>
Expand All @@ -244,20 +267,6 @@ export default function CreateProjectForm({ organizationId, repositories }: Crea
</CardHeader>
<CardContent>
<div className="space-y-4">
<div className="flex items-center space-x-2">
<Controller
name="managedState"
control={control}
render={({ field }) => (
<Checkbox
id="managedState"
checked={field.value}
onCheckedChange={field.onChange}
/>
)}
/>
<Label htmlFor="managedState">Managed State</Label>
</div>
<div>
<Label htmlFor="labels">Labels</Label>
<Controller
Expand All @@ -277,6 +286,12 @@ export default function CreateProjectForm({ organizationId, repositories }: Crea
</div>
</CardContent>
</MotionCard>
<div className="flex justify-end w-full gap-3 mt-6">
<Button type="button" variant="outline" onClick={() => router.back()}>Cancel</Button>
<Button type="submit" disabled={isSubmitting || createProjectMutation.isLoading}>
{isSubmitting || createProjectMutation.isLoading ? "Creating..." : "Create Project"}
</Button>
</div>
</form>
</div>
);
Expand Down
Loading

0 comments on commit d7b2e13

Please sign in to comment.