Skip to content

Commit

Permalink
feature / add settings and connect runs to db
Browse files Browse the repository at this point in the history
  • Loading branch information
psiddharthdesign committed Jul 25, 2024
1 parent cf5aed7 commit dd04a30
Show file tree
Hide file tree
Showing 9 changed files with 398 additions and 111 deletions.
Original file line number Diff line number Diff line change
@@ -1,9 +1,68 @@
'use client';

import { InputTags } from "@/components/InputTags";
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 { updateProjectSettingsAction } from "@/data/user/projects";
import { useSAToastMutation } from "@/hooks/useSAToastMutation";
import { Tables } from "@/lib/database.types";
import { motion } from "framer-motion";
import { useState } from "react";
import { Controller, useForm } from "react-hook-form";

type ProjectSettingsProps = {
project: Tables<'projects'>;
repositoryName: string | null;
};

type ProjectSettingsFormData = {
terraformWorkingDir: string;
labels: string[];
managedState: boolean;
};

export default function ProjectSettings({ project, repositoryName }: ProjectSettingsProps) {
const [isSubmitting, setIsSubmitting] = useState(false);

const { control, handleSubmit, formState: { isDirty } } = useForm<ProjectSettingsFormData>({
defaultValues: {
terraformWorkingDir: project.terraform_working_dir || '',
labels: project.labels || [],
managedState: project.is_managing_state || false,
},
});

const updateProjectSettingsMutation = useSAToastMutation(
async (data: ProjectSettingsFormData) => {
const result = await updateProjectSettingsAction({
projectId: project.id,
terraformWorkingDir: data.terraformWorkingDir,
labels: data.labels,
managedState: data.managedState,
});
return result;
},
{
loadingMessage: "Updating project settings...",
successMessage: "Project settings updated successfully!",
errorMessage: "Failed to update project settings",
}
);

const onSubmit = async (data: ProjectSettingsFormData) => {
setIsSubmitting(true);
try {
await updateProjectSettingsMutation.mutateAsync(data);
} catch (error) {
console.error("Error updating project settings:", error);
} finally {
setIsSubmitting(false);
}
};

export default function ProjectSettings() {
return (
<motion.div
initial={{ opacity: 0, y: 10 }}
Expand All @@ -12,24 +71,103 @@ export default function ProjectSettings() {
transition={{ duration: 0.1 }}
>
<Card className="w-full">
<motion.div
initial={{ opacity: 0, y: -5 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.15, delay: 0.1 }}
>
<CardHeader>
<CardTitle>Project Settings</CardTitle>
<CardDescription>Manage settings for your project</CardDescription>
</CardHeader>
</motion.div>
<CardHeader>
<CardTitle>Project Settings</CardTitle>
<CardDescription>Manage settings for your project</CardDescription>
</CardHeader>
<CardContent>
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ duration: 0.15, delay: 0.2 }}
>
{/* Add your project settings management component here */}
</motion.div>
<form onSubmit={handleSubmit(onSubmit)} className="space-y-6">
<div className="grid grid-cols-2 gap-6">
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ duration: 0.15, delay: 0.1 }}
>
<Label htmlFor="name">Project Name</Label>
<Input id="name" value={project.name} disabled />
</motion.div>

<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ duration: 0.15, delay: 0.2 }}
>
<Label htmlFor="repo">Repository</Label>
<Input id="repo" value={repositoryName || 'N/A'} disabled />
</motion.div>
</div>

<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ duration: 0.15, delay: 0.3 }}
className="flex items-center space-x-2"
>
<Controller
name="managedState"
control={control}
render={({ field }) => (
<Checkbox
id="managedState"
checked={field.value}
onCheckedChange={field.onChange}
disabled
/>
)}
/>
<Label htmlFor="managedState">Managed State</Label>
</motion.div>

<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ duration: 0.15, delay: 0.4 }}
>
<Label htmlFor="terraformWorkingDir">Terraform Working Directory</Label>
<Controller
name="terraformWorkingDir"
control={control}
render={({ field }) => (
<Input id="terraformWorkingDir" {...field} />
)}
/>
</motion.div>

<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ duration: 0.15, delay: 0.5 }}
>
<Label htmlFor="labels">Labels</Label>
<Controller
name="labels"
control={control}
render={({ field }) => (
<InputTags
id="labels"
value={field.value}
onChange={field.onChange}
placeholder="Add labels"
className="mt-1"
/>
)}
/>
</motion.div>

<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ duration: 0.15, delay: 0.6 }}
className="flex justify-end"
>
<Button
type="submit"
disabled={!isDirty || isSubmitting || updateProjectSettingsMutation.isLoading}
>
{isSubmitting || updateProjectSettingsMutation.isLoading ? "Saving..." : "Save Changes"}
</Button>
</motion.div>
</form>
</CardContent>
</Card>
</motion.div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
'use client';

import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import { Tables } from "@/lib/database.types";
import { motion } from "framer-motion";
import { Run, RunsTable } from "./RunsTable";
import { RunsTable } from "./RunsTable";

export default function RunsDetails({ runs }: { runs: Run[] }) {
export default function RunDetails({ runs, project }: { runs: Tables<'digger_runs'>[], project: Tables<'projects'> }) {
return (
<motion.div
initial={{ opacity: 0, y: 10 }}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,27 +1,23 @@
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";

export type Run = {
runId: string;
commitId: string;
status: string;
date: string;
user: string;
};
import { Tables } from "@/lib/database.types";
import { motion } from "framer-motion";
import { Activity } from "lucide-react";
import moment from "moment";

type StatusColor = {
[key: string]: string;
};

const statusColors: StatusColor = {
queued: 'bg-yellow-200/50 text-yellow-800 dark:bg-yellow-900/50 dark:text-yellow-200',
'pending approval': 'bg-blue-200/50 text-blue-800 dark:bg-blue-900/50 dark:text-blue-200',
'pending_approval': 'bg-blue-200/50 text-blue-800 dark:bg-blue-900/50 dark:text-blue-200',
running: 'bg-purple-200/50 text-purple-800 dark:bg-purple-900/50 dark:text-purple-200',
approved: 'bg-green-200/50 text-green-800 dark:bg-green-900/50 dark:text-green-200',
succeeded: 'bg-green-200/50 text-green-800 dark:bg-green-900/50 dark:text-green-200',
failed: 'bg-red-200/50 text-red-800 dark:bg-red-900/50 dark:text-red-200',
};

export const RunsTable = ({ runs }: { runs: Run[] }) => (
export const RunsTable = ({ runs }: { runs: Tables<'digger_runs'>[] }) => (
<Table>
<TableHeader>
<TableRow>
Expand All @@ -35,21 +31,40 @@ export const RunsTable = ({ runs }: { runs: Run[] }) => (
<TableBody>
{runs.length > 0 ? (
runs.map((run) => (
<TableRow key={run.runId}>
<TableCell>{run.runId}</TableCell>
<TableCell>{run.commitId}</TableCell>
<TableRow key={run.id}>
<TableCell >{run.id.length > 8 ? `${run.id.substring(0, 8)}...` : run.id}</TableCell>
<TableCell>{run.commit_id}</TableCell>
<TableCell>
<span className={`px-2 py-1 rounded-full text-xs font-medium ${statusColors[run.status.toLowerCase()] || ''}`}>
{run.status.toUpperCase()}
</span>
</TableCell>
<TableCell>{run.date}</TableCell>
<TableCell>{run.user}</TableCell>
<TableCell>{moment(run.created_at).fromNow()}</TableCell>
<TableCell>{run.approval_author}</TableCell>
</TableRow>
))
) : (
<TableRow>
<TableCell colSpan={5} className="text-center">No runs available</TableCell>
<TableCell colSpan={5}>
<motion.div
className="flex flex-col items-center justify-center h-64 text-center"
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5 }}
>
<motion.div
className="rounded-full bg-gray-100 p-4 dark:bg-gray-800"
whileHover={{ scale: 1.05 }}
whileTap={{ scale: 0.95 }}
>
<Activity className="h-8 w-8 text-gray-400" />
</motion.div>
<h3 className="mt-4 text-lg font-semibold text-gray-900 dark:text-gray-100">No runs available</h3>
<p className="mt-2 text-sm text-gray-500 dark:text-gray-400">
Runs will appear here once they are initiated.
</p>
</motion.div>
</TableCell>
</TableRow>
)}
</TableBody>
Expand Down
Loading

0 comments on commit dd04a30

Please sign in to comment.