CreateAwsCognitoAuthDialog.tsx192 lines · main
1import { zodResolver } from '@hookform/resolvers/zod'
2import { useParams } from 'common'
3import { Trash } from 'lucide-react'
4import { useEffect } from 'react'
5import { SubmitHandler, useForm } from 'react-hook-form'
6import { toast } from 'sonner'
7import {
8 Button,
9 Dialog,
10 DialogContent,
11 DialogDescription,
12 DialogFooter,
13 DialogHeader,
14 DialogSection,
15 DialogTitle,
16 Form,
17 FormControl,
18 FormField,
19 Input,
20 Separator,
21} from 'ui'
22import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
23import * as z from 'zod'
24
25import { AwsRegionSelector } from './AwsRegionSelector'
26import { useCreateThirdPartyAuthIntegrationMutation } from '@/data/third-party-auth/integration-create-mutation'
27
28interface CreateAwsCognitoAuthIntegrationProps {
29 visible: boolean
30 onClose: () => void
31 // TODO: Remove this if this Dialog is only used for creating.
32 onDelete: () => void
33}
34
35const FORM_ID = 'create-aws-cognito-auth-integration-form'
36
37const FormSchema = z.object({
38 enabled: z.boolean(),
39 awsCognitoUserPoolId: z
40 .string()
41 .trim()
42 .min(1)
43 .regex(/^[A-Za-z0-9-_]+$/, 'The project ID contains invalid characters.'), // Only allow alphanumeric characters and hyphens.
44 awsRegion: z.string(),
45})
46
47export const CreateAwsCognitoAuthIntegrationDialog = ({
48 visible,
49 onClose,
50 onDelete,
51}: CreateAwsCognitoAuthIntegrationProps) => {
52 // TODO: Remove this if this Dialog is only used for creating.
53 const isCreating = true
54
55 const { ref: projectRef } = useParams()
56 const { mutate: createAuthIntegration, isPending } = useCreateThirdPartyAuthIntegrationMutation({
57 onSuccess: () => {
58 toast.success(`Successfully created a new Amazon Cognito Auth integration.`)
59 onClose()
60 },
61 })
62
63 const form = useForm<z.infer<typeof FormSchema>>({
64 resolver: zodResolver(FormSchema as any),
65 defaultValues: {
66 enabled: true,
67 awsCognitoUserPoolId: '',
68 awsRegion: 'us-east-1',
69 },
70 })
71
72 useEffect(() => {
73 if (visible) {
74 form.reset({
75 enabled: true,
76 awsCognitoUserPoolId: '',
77 awsRegion: 'us-east-1',
78 })
79 // the form input doesn't exist when the form is reset
80 setTimeout(() => {
81 form.setFocus('awsCognitoUserPoolId')
82 }, 25)
83 }
84 }, [visible])
85
86 const onSubmit: SubmitHandler<z.infer<typeof FormSchema>> = async (values) => {
87 createAuthIntegration({
88 projectRef: projectRef!,
89 oidcIssuerUrl: `https://cognito-idp.${values.awsRegion}.amazonaws.com/${values.awsCognitoUserPoolId}`,
90 })
91 }
92
93 const awsRegion = form.watch('awsRegion')
94
95 return (
96 <Dialog open={visible} onOpenChange={() => onClose()}>
97 <DialogContent size="large">
98 <DialogHeader>
99 <DialogTitle className="truncate">
100 {isCreating
101 ? `Add new Amazon Cognito Auth connection`
102 : `Update existing Amazon Cognito Auth connection`}
103 </DialogTitle>
104 <DialogDescription>
105 By adding an Amazon Cognito Auth connection, you can authenticate users using Amazon
106 Cognito User Pools.
107 </DialogDescription>
108 </DialogHeader>
109 <Separator />
110 <DialogSection>
111 <Form {...form}>
112 <form id={FORM_ID} onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
113 {/* Enabled flag can't be changed for now because there's no update API call for integrations */}
114 {/* <FormField
115 key="enabled"
116 control={form.control}
117 name="enabled"
118 render={({ field }) => (
119 <FormItemLayout
120 className="px-8"
121 label={`Enable Amazon Cognito Auth Connection`}
122 layout="flex"
123 >
124 <FormControl>
125 <Switch
126 checked={field.value}
127 onCheckedChange={field.onChange}
128 disabled={field.disabled}
129 />
130 </FormControl>
131 </FormItemLayout>
132 )}
133 />
134 <Separator /> */}
135 <p className="text-sm text-foreground-light">
136 This will enable a JWT token from Amazon Cognito project to access data from this
137 Briven project.
138 </p>
139 <FormField
140 key="awsCognitoUserPoolId"
141 control={form.control}
142 name="awsCognitoUserPoolId"
143 render={({ field }) => (
144 <FormItemLayout label="Amazon Cognito User Pool ID">
145 <div className="flex flex-row">
146 <Button
147 type="default"
148 size="small"
149 className="px-2 text-foreground-light rounded-r-none"
150 onClick={() => form.setFocus('awsCognitoUserPoolId')}
151 >
152 https://cognito-idp.{awsRegion}.amazonaws.com/
153 </Button>
154 <FormControl>
155 <Input className="rounded-l-none border-l-0 z-50" {...field} />
156 </FormControl>
157 </div>
158 </FormItemLayout>
159 )}
160 />
161 <FormField
162 control={form.control}
163 name="awsRegion"
164 render={({ field }) => (
165 <FormItemLayout label="AWS Region">
166 <AwsRegionSelector value={field.value} onChange={field.onChange} />
167 </FormItemLayout>
168 )}
169 />
170 </form>
171 </Form>
172 </DialogSection>
173 <DialogFooter>
174 {!isCreating && (
175 <div className="flex-1">
176 <Button type="danger" onClick={() => onDelete()} icon={<Trash />}>
177 Remove connection
178 </Button>
179 </div>
180 )}
181
182 <Button disabled={isPending} type="default" onClick={() => onClose()}>
183 Cancel
184 </Button>
185 <Button form={FORM_ID} htmlType="submit" disabled={isPending} loading={isPending}>
186 {isCreating ? 'Create connection' : 'Update connection'}
187 </Button>
188 </DialogFooter>
189 </DialogContent>
190 </Dialog>
191 )
192}