diff --git a/src/app/(dynamic-pages)/(authenticated-pages)/(application-pages)/project/[projectSlug]/(specific-project-pages)/ProjectSettings.tsx b/src/app/(dynamic-pages)/(authenticated-pages)/(application-pages)/project/[projectSlug]/(specific-project-pages)/ProjectSettings.tsx index e40914c4..71a4d967 100644 --- a/src/app/(dynamic-pages)/(authenticated-pages)/(application-pages)/project/[projectSlug]/(specific-project-pages)/ProjectSettings.tsx +++ b/src/app/(dynamic-pages)/(authenticated-pages)/(application-pages)/project/[projectSlug]/(specific-project-pages)/ProjectSettings.tsx @@ -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({ + 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 ( - - - Project Settings - Manage settings for your project - - + + Project Settings + Manage settings for your project + - - {/* Add your project settings management component here */} - +
+
+ + + + + + + + + +
+ + + ( + + )} + /> + + + + + + ( + + )} + /> + + + + + ( + + )} + /> + + + + + +
diff --git a/src/app/(dynamic-pages)/(authenticated-pages)/(application-pages)/project/[projectSlug]/(specific-project-pages)/ProjectDetails.tsx b/src/app/(dynamic-pages)/(authenticated-pages)/(application-pages)/project/[projectSlug]/(specific-project-pages)/RunDetails.tsx similarity index 86% rename from src/app/(dynamic-pages)/(authenticated-pages)/(application-pages)/project/[projectSlug]/(specific-project-pages)/ProjectDetails.tsx rename to src/app/(dynamic-pages)/(authenticated-pages)/(application-pages)/project/[projectSlug]/(specific-project-pages)/RunDetails.tsx index d975ec9d..7f46d6dd 100644 --- a/src/app/(dynamic-pages)/(authenticated-pages)/(application-pages)/project/[projectSlug]/(specific-project-pages)/ProjectDetails.tsx +++ b/src/app/(dynamic-pages)/(authenticated-pages)/(application-pages)/project/[projectSlug]/(specific-project-pages)/RunDetails.tsx @@ -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 ( ( +export const RunsTable = ({ runs }: { runs: Tables<'digger_runs'>[] }) => ( @@ -35,21 +31,40 @@ export const RunsTable = ({ runs }: { runs: Run[] }) => ( {runs.length > 0 ? ( runs.map((run) => ( - - {run.runId} - {run.commitId} + + {run.id.length > 8 ? `${run.id.substring(0, 8)}...` : run.id} + {run.commit_id} {run.status.toUpperCase()} - {run.date} - {run.user} + {moment(run.created_at).fromNow()} + {run.approval_author} )) ) : ( - No runs available + + + + + +

No runs available

+

+ Runs will appear here once they are initiated. +

+
+
)}
diff --git a/src/app/(dynamic-pages)/(authenticated-pages)/(application-pages)/project/[projectSlug]/(specific-project-pages)/page.tsx b/src/app/(dynamic-pages)/(authenticated-pages)/(application-pages)/project/[projectSlug]/(specific-project-pages)/page.tsx index 7ac3f353..1dc70cc8 100644 --- a/src/app/(dynamic-pages)/(authenticated-pages)/(application-pages)/project/[projectSlug]/(specific-project-pages)/page.tsx +++ b/src/app/(dynamic-pages)/(authenticated-pages)/(application-pages)/project/[projectSlug]/(specific-project-pages)/page.tsx @@ -23,79 +23,83 @@ export async function generateMetadata({ } -import ProjectDetails from "./ProjectDetails"; -import { Run } from "./RunsTable"; +import { getRunsByProjectId } from "@/data/user/runs"; +import RunDetails from "./RunDetails"; -const dummyRuns: Run[] = [ - { - runId: "run-001", - commitId: "abc123", - status: "queued", - date: "2023-06-01", - user: "Alice" - }, - { - runId: "run-002", - commitId: "def456", - status: "pending approval", - date: "2023-06-02", - user: "Bob" - }, - { - runId: "run-003", - commitId: "ghi789", - status: "running", - date: "2023-06-03", - user: "Charlie" - }, - { - runId: "run-004", - commitId: "jkl012", - status: "approved", - date: "2023-06-04", - user: "Diana" - }, - { - runId: "run-005", - commitId: "mno345", - status: "succeeded", - date: "2023-06-05", - user: "Ethan" - }, - { - runId: "run-006", - commitId: "pqr678", - status: "failed", - date: "2023-06-06", - user: "Fiona" - }, - { - runId: "run-007", - commitId: "stu901", - status: "queued", - date: "2023-06-07", - user: "George" - }, - { - runId: "run-008", - commitId: "vwx234", - status: "running", - date: "2023-06-08", - user: "Hannah" - } -]; +// const dummyRuns: Run[] = [ +// { +// runId: "run-001", +// commitId: "abc123", +// status: "queued", +// date: "2023-06-01", +// user: "Alice" +// }, +// { +// runId: "run-002", +// commitId: "def456", +// status: "pending approval", +// date: "2023-06-02", +// user: "Bob" +// }, +// { +// runId: "run-003", +// commitId: "ghi789", +// status: "running", +// date: "2023-06-03", +// user: "Charlie" +// }, +// { +// runId: "run-004", +// commitId: "jkl012", +// status: "approved", +// date: "2023-06-04", +// user: "Diana" +// }, +// { +// runId: "run-005", +// commitId: "mno345", +// status: "succeeded", +// date: "2023-06-05", +// user: "Ethan" +// }, +// { +// runId: "run-006", +// commitId: "pqr678", +// status: "failed", +// date: "2023-06-06", +// user: "Fiona" +// }, +// { +// runId: "run-007", +// commitId: "stu901", +// status: "queued", +// date: "2023-06-07", +// user: "George" +// }, +// { +// runId: "run-008", +// commitId: "vwx234", +// status: "running", +// date: "2023-06-08", +// user: "Hannah" +// } +// ]; -const runs = dummyRuns; +// const runs = dummyRuns; export default async function ProjectPage({ params }: { params: unknown }) { const { projectSlug } = projectSlugParamSchema.parse(params); const slimProject = await getSlimProjectBySlug(projectSlug); const project = await getProjectById(slimProject.id); + const runs = await getRunsByProjectId(slimProject.id); return (
- +
); }; \ No newline at end of file diff --git a/src/app/(dynamic-pages)/(authenticated-pages)/(application-pages)/project/[projectSlug]/(specific-project-pages)/settings/page.tsx b/src/app/(dynamic-pages)/(authenticated-pages)/(application-pages)/project/[projectSlug]/(specific-project-pages)/settings/page.tsx index ac265433..84a5945e 100644 --- a/src/app/(dynamic-pages)/(authenticated-pages)/(application-pages)/project/[projectSlug]/(specific-project-pages)/settings/page.tsx +++ b/src/app/(dynamic-pages)/(authenticated-pages)/(application-pages)/project/[projectSlug]/(specific-project-pages)/settings/page.tsx @@ -1,4 +1,5 @@ -import { getSlimProjectBySlug } from '@/data/user/projects'; +import { getProjectById, getSlimProjectBySlug } from '@/data/user/projects'; +import { getRepoDetails } from '@/data/user/repos'; import { projectSlugParamSchema } from '@/utils/zod-schemas/params'; import ProjectSettings from '../ProjectSettings'; @@ -6,10 +7,12 @@ import ProjectSettings from '../ProjectSettings'; export default async function ProjectSettingsPage({ params }: { params: unknown }) { const { projectSlug } = projectSlugParamSchema.parse(params); - const project = await getSlimProjectBySlug(projectSlug); + const projectData = await getSlimProjectBySlug(projectSlug); + const project = await getProjectById(projectData.id); + const repository = await getRepoDetails(project.repo_id); return (
- +
); } diff --git a/src/components/InputTags.tsx b/src/components/InputTags.tsx index 4146e62e..241ab65a 100644 --- a/src/components/InputTags.tsx +++ b/src/components/InputTags.tsx @@ -3,7 +3,7 @@ import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { Input, InputProps } from "@/components/ui/input"; -import { XIcon } from "lucide-react"; +import { Edit2, XIcon } from "lucide-react"; import { Dispatch, SetStateAction, forwardRef, useState } from "react"; type InputTagsProps = InputProps & { @@ -14,15 +14,28 @@ type InputTagsProps = InputProps & { export const InputTags = forwardRef( ({ value, onChange, ...props }, ref) => { const [pendingDataPoint, setPendingDataPoint] = useState(""); + const [editingIndex, setEditingIndex] = useState(null); - const addPendingDataPoint = () => { + const addOrUpdateDataPoint = () => { if (pendingDataPoint.trim()) { - const newDataPoints = new Set([...value, pendingDataPoint.trim()]); - onChange(Array.from(newDataPoints)); + if (editingIndex !== null) { + const newDataPoints = [...value]; + newDataPoints[editingIndex] = pendingDataPoint.trim(); + onChange(Array.from(new Set(newDataPoints))); + setEditingIndex(null); + } else { + const newDataPoints = new Set([...value, pendingDataPoint.trim()]); + onChange(Array.from(newDataPoints)); + } setPendingDataPoint(""); } }; + const editTag = (index: number) => { + setPendingDataPoint(value[index]); + setEditingIndex(index); + }; + return ( <>
@@ -32,7 +45,7 @@ export const InputTags = forwardRef( onKeyDown={(e) => { if (e.key === "Enter") { e.preventDefault(); - addPendingDataPoint(); + addOrUpdateDataPoint(); } }} className="rounded-r-none" @@ -42,17 +55,24 @@ export const InputTags = forwardRef(
{value.length > 0 && ( -
+
{value.map((item, idx) => ( {item} +