import { useEffect } from "react"; import { Controller, useForm } from "react-hook-form"; import { SiOctopusdeploy } from "react-icons/si"; import { zodResolver } from "@hookform/resolvers/zod"; import { useNavigate, useSearch } from "@tanstack/react-router"; import { z } from "zod"; import { createNotification } from "@app/components/notifications"; import { Button, Card, CardTitle, FilterableSelect, FormControl, Spinner } from "@app/components/v2"; import { SecretPathInput } from "@app/components/v2/SecretPathInput"; import { ROUTE_PATHS } from "@app/const/routes"; import { useWorkspace } from "@app/context"; import { useCreateIntegration, useGetIntegrationAuthApps } from "@app/hooks/api"; import { useGetIntegrationAuthOctopusDeployScopeValues, useGetIntegrationAuthOctopusDeploySpaces } from "@app/hooks/api/integrationAuth/queries"; import { OctopusDeployScope } from "@app/hooks/api/integrationAuth/types"; const formSchema = z.object({ scope: z.nativeEnum(OctopusDeployScope), secretPath: z.string().default("/"), sourceEnvironment: z.object({ name: z.string(), slug: z.string() }), targetSpace: z.object({ Name: z.string(), Id: z.string() }), targetResource: z.object({ appId: z.string().optional(), name: z.string() }), targetEnvironments: z.object({ Name: z.string(), Id: z.string() }).array().optional(), targetRoles: z.object({ Name: z.string(), Id: z.string() }).array().optional(), targetMachines: z.object({ Name: z.string(), Id: z.string() }).array().optional(), targetProcesses: z .object({ Name: z.string(), Id: z.string(), ProcessType: z.string() }) .array() .optional(), targetActions: z.object({ Name: z.string(), Id: z.string() }).array().optional(), targetChannels: z.object({ Name: z.string(), Id: z.string() }).array().optional() }); type TFormData = z.infer; export const OctopusDeployConfigurePage = () => { const navigate = useNavigate(); const createIntegration = useCreateIntegration(); const { watch, control, reset, handleSubmit } = useForm({ resolver: zodResolver(formSchema), defaultValues: { secretPath: "/", scope: OctopusDeployScope.Project } }); const { currentWorkspace } = useWorkspace(); const integrationAuthId = useSearch({ from: ROUTE_PATHS.SecretManager.Integratons.OctopusDeployCloudConfigurePage.id, select: (el) => el.integrationAuthId }); const { data: octopusDeploySpaces, isPending: isLoadingOctopusDeploySpaces } = useGetIntegrationAuthOctopusDeploySpaces((integrationAuthId as string) ?? ""); const currentSpace = watch("targetSpace", octopusDeploySpaces?.[0]); const currentScope = watch("scope"); const sourceEnv = watch("sourceEnvironment"); const { data: octopusDeployResources, isPending: isOctopusDeployResourcesLoading } = useGetIntegrationAuthApps( { integrationAuthId, workspaceSlug: currentSpace?.Name // scope once we support other resources than project }, { enabled: Boolean(currentSpace ?? octopusDeploySpaces?.find((space) => space.IsDefault)) } ); const currentResource = watch("targetResource", octopusDeployResources?.[0]); const { data: octopusDeployScopeValues, isPending: isOctopusDeployScopeValuesLoading } = useGetIntegrationAuthOctopusDeployScopeValues( { integrationAuthId, spaceId: currentSpace?.Id, resourceId: currentResource.appId!, scope: currentScope }, { enabled: Boolean(currentSpace && currentResource) } ); const onSubmit = async ({ sourceEnvironment, secretPath, targetEnvironments, targetResource, targetSpace, targetChannels, targetActions, targetMachines, targetProcesses, targetRoles, scope }: TFormData) => { try { await createIntegration.mutateAsync({ integrationAuthId, isActive: true, scope, app: targetResource.name, appId: targetResource.appId, targetEnvironment: targetSpace.Name, targetEnvironmentId: targetSpace.Id, metadata: { octopusDeployScopeValues: { Environment: targetEnvironments?.map(({ Id }) => Id), Action: targetActions?.map(({ Id }) => Id), Channel: targetChannels?.map(({ Id }) => Id), ProcessOwner: targetProcesses?.map(({ Id }) => Id), Role: targetRoles?.map(({ Id }) => Id), Machine: targetMachines?.map(({ Id }) => Id) } }, sourceEnvironment: sourceEnvironment.slug, secretPath }); createNotification({ type: "success", text: "Successfully created integration" }); navigate({ to: "/secret-manager/$projectId/integrations", params: { projectId: currentWorkspace.id } }); } catch (err) { createNotification({ type: "error", text: "Failed to create integration" }); console.error(err); } }; useEffect(() => { if (!octopusDeployResources || !octopusDeploySpaces || !currentWorkspace) return; reset({ targetResource: octopusDeployResources[0], targetSpace: octopusDeploySpaces.find((space) => space.IsDefault), sourceEnvironment: currentWorkspace.environments[0], secretPath: "/", scope: OctopusDeployScope.Project }); }, [octopusDeploySpaces, octopusDeployResources, currentWorkspace]); if (isLoadingOctopusDeploySpaces || isOctopusDeployResourcesLoading) return (
); return (
Octopus Deploy Integration
( option.slug} value={value} getOptionLabel={(option) => option.name} onChange={onChange} options={currentWorkspace?.environments} placeholder="Select a project environment" isDisabled={!currentWorkspace?.environments.length} /> )} /> ( )} />
Sync To
( option.Id} value={value} getOptionLabel={(option) => option.Name} onChange={onChange} options={octopusDeploySpaces} placeholder={ octopusDeploySpaces?.length ? "Select a space..." : "No spaces found..." } isDisabled={!octopusDeploySpaces?.length} /> )} /> ( option.appId!} value={value} getOptionLabel={(option) => option.name} onChange={onChange} options={octopusDeployResources} placeholder={ octopusDeployResources?.length ? "Select a project..." : "No projects found..." } isDisabled={!octopusDeployResources?.length} /> )} /> ( option.Name} value={value} getOptionLabel={(option) => option.Name} onChange={onChange} isLoading={isOctopusDeployScopeValuesLoading} options={octopusDeployScopeValues?.Environments} placeholder={ octopusDeployScopeValues?.Environments?.length ? "Select environments..." : "No environments found..." } isDisabled={!octopusDeployScopeValues?.Environments?.length} /> )} /> ( option.Name} value={value} getOptionLabel={(option) => option.Name} onChange={onChange} isLoading={isOctopusDeployScopeValuesLoading} options={octopusDeployScopeValues?.Roles} placeholder={ octopusDeployScopeValues?.Roles?.length ? "Select target tags..." : "No target tags found..." } isDisabled={!octopusDeployScopeValues?.Roles?.length} /> )} /> ( option.Name} value={value} getOptionLabel={(option) => option.Name} onChange={onChange} isLoading={isOctopusDeployScopeValuesLoading} options={octopusDeployScopeValues?.Machines} placeholder={ octopusDeployScopeValues?.Machines?.length ? "Select targets..." : "No targets found..." } isDisabled={!octopusDeployScopeValues?.Machines?.length} /> )} /> ( option.Name} value={value} getOptionLabel={(option) => option.Name} onChange={onChange} isLoading={isOctopusDeployScopeValuesLoading} options={octopusDeployScopeValues?.Processes} placeholder={ octopusDeployScopeValues?.Processes?.length ? "Select processes..." : "No processes found..." } isDisabled={!octopusDeployScopeValues?.Processes?.length} /> )} /> ( option.Name} value={value} getOptionLabel={(option) => option.Name} onChange={onChange} isLoading={isOctopusDeployScopeValuesLoading} options={octopusDeployScopeValues?.Actions} placeholder={ octopusDeployScopeValues?.Actions?.length ? "Select deployment steps..." : "No deployment steps found..." } isDisabled={!octopusDeployScopeValues?.Actions?.length} /> )} /> ( option.Name} value={value} getOptionLabel={(option) => option.Name} onChange={onChange} isLoading={isOctopusDeployScopeValuesLoading} options={octopusDeployScopeValues?.Channels} placeholder={ octopusDeployScopeValues?.Channels?.length ? "Select channels..." : "No channels found..." } isDisabled={!octopusDeployScopeValues?.Channels?.length} /> )} />
); };