CreateAwsCognitoAuthDialog.tsx 6.2 KB

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