diff --git a/apps/webservice/src/app/[workspaceSlug]/(app)/systems/[systemSlug]/_components/EditAgentConfigDialog.tsx b/apps/webservice/src/app/[workspaceSlug]/(app)/systems/[systemSlug]/_components/EditAgentConfigDialog.tsx deleted file mode 100644 index 7f575931d..000000000 --- a/apps/webservice/src/app/[workspaceSlug]/(app)/systems/[systemSlug]/_components/EditAgentConfigDialog.tsx +++ /dev/null @@ -1,137 +0,0 @@ -"use client"; - -import type * as schema from "@ctrlplane/db/schema"; -import { useState } from "react"; -import Link from "next/link"; -import { useRouter } from "next/navigation"; -import { z } from "zod"; - -import { Button } from "@ctrlplane/ui/button"; -import { - Dialog, - DialogContent, - DialogDescription, - DialogFooter, - DialogHeader, - DialogTitle, - DialogTrigger, -} from "@ctrlplane/ui/dialog"; -import { Form, FormField, useForm } from "@ctrlplane/ui/form"; - -import { JobAgentGitHubConfig } from "~/components/form/job-agent/JobAgentGitHubConfig"; -import { JobAgentKubernetesConfig } from "~/components/form/job-agent/JobAgentKubernetesConfig"; -import { JobAgentSelectorInput } from "~/components/form/job-agent/JobAgentSelector"; - -type EditAgentConfigDialogProps = { - jobAgents: schema.JobAgent[]; - jobAgent: schema.JobAgent; - value: Record; - workspace: { id: string; slug: string }; - onSubmit: (data: { - jobAgentId: string; - config: Record; - }) => Promise; - children: React.ReactNode; -}; - -export const EditAgentConfigDialog: React.FC = ({ - jobAgents, - jobAgent, - value, - workspace, - onSubmit, - children, -}) => { - const form = useForm({ - schema: z.object({ - jobAgentId: z.string().uuid(), - config: z.record(z.any()), - }), - defaultValues: { - jobAgentId: jobAgent.id, - config: value, - }, - }); - const [open, setOpen] = useState(false); - const router = useRouter(); - - const onFormSubmit = form.handleSubmit((data) => - onSubmit({ - jobAgentId: data.jobAgentId, - config: data.config, - }).then(() => { - router.refresh(); - setOpen(false); - }), - ); - - const { jobAgentId } = form.watch(); - const selectedJobAgent = jobAgents.find((j) => j.id === jobAgentId); - - return ( - - {children} - - - Edit agent - - Edit the agent configuration for this deployment. - - -
- - ( - - )} - /> - ( -
- {selectedJobAgent?.type === "github-app" && ( -
- -
- )} - - {selectedJobAgent?.type === "kubernetes-job" && ( - - )} -
- )} - /> - - - - -
- - - - - -
- ); -}; diff --git a/apps/webservice/src/app/[workspaceSlug]/(app)/systems/[systemSlug]/deployments/[deploymentSlug]/NavigationMenuAction.tsx b/apps/webservice/src/app/[workspaceSlug]/(app)/systems/[systemSlug]/deployments/[deploymentSlug]/NavigationMenuAction.tsx index 7968513bf..a5508607d 100644 --- a/apps/webservice/src/app/[workspaceSlug]/(app)/systems/[systemSlug]/deployments/[deploymentSlug]/NavigationMenuAction.tsx +++ b/apps/webservice/src/app/[workspaceSlug]/(app)/systems/[systemSlug]/deployments/[deploymentSlug]/NavigationMenuAction.tsx @@ -1,7 +1,7 @@ "use client"; import React from "react"; -import { usePathname } from "next/navigation"; +import { useParams, usePathname } from "next/navigation"; import { Button } from "@ctrlplane/ui/button"; @@ -15,6 +15,7 @@ export const NavigationMenuAction: React.FC<{ deploymentId: string; systemId: string; }> = ({ deploymentId, systemId }) => { + const { workspaceSlug } = useParams<{ workspaceSlug: string }>(); const pathname = usePathname(); const isVariablesActive = pathname.includes("variables"); const isReleaseChannelsActive = pathname.includes("release-channels"); @@ -24,8 +25,13 @@ export const NavigationMenuAction: React.FC<{ api.deployment.releaseChannel.list.byDeploymentId.useQuery(deploymentId); const releaseChannels = releaseChannelsQ.data ?? []; - const runbooksQ = api.runbook.bySystemId.useQuery(systemId); - const runbooks = runbooksQ.data ?? []; + const workspaceQ = api.workspace.bySlug.useQuery(workspaceSlug); + const workspace = workspaceQ.data; + + const jobAgentsQ = api.job.agent.byWorkspaceId.useQuery(workspace?.id ?? "", { + enabled: workspace != null, + }); + const jobAgents = jobAgentsQ.data ?? []; return (
@@ -48,8 +54,12 @@ export const NavigationMenuAction: React.FC<{ )} - {isHooksActive && ( - + {isHooksActive && workspace != null && ( + diff --git a/apps/webservice/src/app/[workspaceSlug]/(app)/systems/[systemSlug]/deployments/[deploymentSlug]/hooks/CreateHookDialog.tsx b/apps/webservice/src/app/[workspaceSlug]/(app)/systems/[systemSlug]/deployments/[deploymentSlug]/hooks/CreateHookDialog.tsx index fee6f8e1b..b2600df1f 100644 --- a/apps/webservice/src/app/[workspaceSlug]/(app)/systems/[systemSlug]/deployments/[deploymentSlug]/hooks/CreateHookDialog.tsx +++ b/apps/webservice/src/app/[workspaceSlug]/(app)/systems/[systemSlug]/deployments/[deploymentSlug]/hooks/CreateHookDialog.tsx @@ -1,12 +1,12 @@ "use client"; import type * as SCHEMA from "@ctrlplane/db/schema"; +import type { HookAction } from "@ctrlplane/validators/events"; import { useState } from "react"; import { useRouter } from "next/navigation"; -import { IconPlus, IconSelector, IconX } from "@tabler/icons-react"; +import { IconSelector } from "@tabler/icons-react"; import { z } from "zod"; -import { Badge } from "@ctrlplane/ui/badge"; import { Button } from "@ctrlplane/ui/button"; import { Command, @@ -30,64 +30,74 @@ import { FormItem, FormLabel, FormMessage, - useFieldArray, useForm, } from "@ctrlplane/ui/form"; import { Input } from "@ctrlplane/ui/input"; -import { Label } from "@ctrlplane/ui/label"; import { Popover, PopoverContent, PopoverTrigger } from "@ctrlplane/ui/popover"; -import { hookActions, hookActionsList } from "@ctrlplane/validators/events"; +import { + hookActions, + hookActionsList, + RunhookVariables, +} from "@ctrlplane/validators/events"; +import { JobAgentConfig } from "~/components/form/job-agent/JobAgentConfig"; +import { JobAgentSelector } from "~/components/form/job-agent/JobAgentSelector"; import { api } from "~/trpc/react"; type CreateHookDialogProps = { deploymentId: string; - runbooks: SCHEMA.Runbook[]; + jobAgents: SCHEMA.JobAgent[]; + workspace: SCHEMA.Workspace; children: React.ReactNode; }; const schema = z.object({ name: z.string().min(1), action: hookActions, - runbookIds: z.array(z.object({ id: z.string().uuid() })), + jobAgentId: z.string().nullable(), + jobAgentConfig: z.record(z.any()).nullable(), }); +const defaultValues = { + name: "", + action: "", + jobAgentId: null, + jobAgentConfig: {}, +}; + export const CreateHookDialog: React.FC = ({ deploymentId, - runbooks, + jobAgents, + workspace, children, }) => { const [open, setOpen] = useState(false); const [actionsOpen, setActionsOpen] = useState(false); - const [runbooksOpen, setRunbooksOpen] = useState(false); const createHook = api.deployment.hook.create.useMutation(); const utils = api.useUtils(); const router = useRouter(); - const defaultValues = { name: "", action: "", runbookIds: [] }; const form = useForm({ schema, defaultValues }); const onSubmit = form.handleSubmit((data) => createHook .mutateAsync({ ...data, + variables: RunhookVariables[data.action as HookAction], scopeType: "deployment", scopeId: deploymentId, - runbookIds: data.runbookIds.map((r) => r.id), + jobAgentId: + data.jobAgentId === "" || data.jobAgentId == null + ? undefined + : data.jobAgentId, + jobAgentConfig: data.jobAgentConfig ?? undefined, }) .then(() => utils.deployment.hook.list.invalidate(deploymentId)) .then(() => router.refresh()) .then(() => setOpen(false)), ); - const { fields, append, remove } = useFieldArray({ - control: form.control, - name: "runbookIds", - }); - - const selectedRunbookIds = form.watch("runbookIds").map((r) => r.id); - const unselectedRunbooks = runbooks.filter( - (r) => !selectedRunbookIds.includes(r.id), - ); + const { jobAgentId } = form.watch(); + const jobAgent = jobAgents.find((d) => d.id === jobAgentId); return ( @@ -159,64 +169,66 @@ export const CreateHookDialog: React.FC = ({ )} /> -
- -
- {fields.map((field, index) => ( - { - const runbook = runbooks.find( - (r) => r.id === field.value, - ); - return ( - - {runbook?.name ?? ""} - remove(index)} - /> - - ); - }} - /> - ))} -
-
+ + Attach Runbook + + This runbook will trigger when the hook is triggered. + + - - - - - - - - - {unselectedRunbooks.map((runbook) => ( - { - append({ id: runbook.id }); - setRunbooksOpen(false); - }} - > - {runbook.name} - - ))} - - - - + ( + + Job Agent + + + + + + )} + /> + ( + + Config + + + + + + )} + /> + +
- - - - - - {unselectedRunbooks.map((runbook) => ( - { - append({ id: runbook.id }); - setRunbooksOpen(false); - }} - > - {runbook.name} - - ))} - - - - + +