CreateWorkOSDialog.tsx 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  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. DialogFooter,
  12. DialogHeader,
  13. DialogSection,
  14. DialogTitle,
  15. Form,
  16. FormControl,
  17. FormField,
  18. Input,
  19. Separator,
  20. } from 'ui'
  21. import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
  22. import * as z from 'zod'
  23. import { useCreateThirdPartyAuthIntegrationMutation } from '@/data/third-party-auth/integration-create-mutation'
  24. interface CreateWorkOSIntegrationProps {
  25. visible: boolean
  26. onClose: () => void
  27. // TODO: Remove this if this Dialog is only used for creating.
  28. onDelete: () => void
  29. }
  30. const FORM_ID = 'create-work-os-integration-form'
  31. const WORKOS_ISSUER =
  32. /^https:\/\/(api.workos.com|[a-zA-Z0-9-]+([.][a-zA-Z0-9-]+){2,})\/(sso|user_management)\/(client|project)_[0-7][0-9A-HJKMNP-TV-Z]{25}\/?$/
  33. const FormSchema = z.object({
  34. enabled: z.boolean(),
  35. issuerURL: z
  36. .string()
  37. .trim()
  38. .min(1)
  39. .regex(
  40. WORKOS_ISSUER,
  41. 'WorkOS URL contains invalid characters or does not have the correct structure.'
  42. ),
  43. })
  44. export const CreateWorkOSIntegrationDialog = ({
  45. visible,
  46. onClose,
  47. onDelete,
  48. }: CreateWorkOSIntegrationProps) => {
  49. // TODO: Remove this if this Dialog is only used for creating.
  50. const isCreating = true
  51. const { ref: projectRef } = useParams()
  52. const { mutate: createAuthIntegration, isPending } = useCreateThirdPartyAuthIntegrationMutation({
  53. onSuccess: () => {
  54. toast.success(`Successfully created a new WorkOS integration.`)
  55. onClose()
  56. },
  57. })
  58. const form = useForm<z.infer<typeof FormSchema>>({
  59. resolver: zodResolver(FormSchema as any),
  60. defaultValues: {
  61. enabled: true,
  62. issuerURL: '',
  63. },
  64. })
  65. useEffect(() => {
  66. if (visible) {
  67. form.reset({
  68. enabled: true,
  69. issuerURL: '',
  70. })
  71. // the form input doesn't exist when the form is reset
  72. setTimeout(() => {
  73. form.setFocus('issuerURL')
  74. }, 25)
  75. }
  76. }, [visible])
  77. const onSubmit: SubmitHandler<z.infer<typeof FormSchema>> = async (values) => {
  78. createAuthIntegration({
  79. projectRef: projectRef!,
  80. oidcIssuerUrl: values.issuerURL,
  81. })
  82. }
  83. return (
  84. <Dialog open={visible} onOpenChange={() => onClose()}>
  85. <DialogContent>
  86. <DialogHeader>
  87. <DialogTitle className="truncate">
  88. {isCreating ? `Add new WorkOS connection` : `Update existing WorkOS connection`}
  89. </DialogTitle>
  90. </DialogHeader>
  91. <Separator />
  92. <DialogSection>
  93. <Form {...form}>
  94. <form id={FORM_ID} onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
  95. {/* Enabled flag can't be changed for now because there's no update API call for integrations */}
  96. {/* <FormField
  97. key="enabled"
  98. control={form.control}
  99. name="enabled"
  100. render={({ field }) => (
  101. <FormItemLayout
  102. className="px-8"
  103. label={`Enable Firebase Auth Connection`}
  104. layout="flex"
  105. >
  106. <FormControl>
  107. <Switch
  108. checked={field.value}
  109. onCheckedChange={field.onChange}
  110. disabled={field.disabled}
  111. />
  112. </FormControl>
  113. </FormItemLayout>
  114. )}
  115. />
  116. <Separator /> */}
  117. <p className="text-sm text-foreground-light">
  118. Enables a JWT from WorkOS to access data from this Briven project.
  119. </p>
  120. <FormField
  121. key="issuerURL"
  122. control={form.control}
  123. name="issuerURL"
  124. render={({ field }) => (
  125. <FormItemLayout
  126. label="WorkOS Issuer URL"
  127. description="Obtain your issuer URL from the WorkOS dashboard."
  128. >
  129. <FormControl>
  130. <Input
  131. {...field}
  132. placeholder="https://api.workos.com/user_management/client_ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  133. />
  134. </FormControl>
  135. </FormItemLayout>
  136. )}
  137. />
  138. </form>
  139. </Form>
  140. </DialogSection>
  141. <DialogFooter>
  142. {!isCreating && (
  143. <div className="flex-1">
  144. <Button type="danger" onClick={() => onDelete()} icon={<Trash />}>
  145. Remove connection
  146. </Button>
  147. </div>
  148. )}
  149. <Button disabled={isPending} type="default" onClick={() => onClose()}>
  150. Cancel
  151. </Button>
  152. <Button form={FORM_ID} htmlType="submit" disabled={isPending} loading={isPending}>
  153. {isCreating ? 'Create connection' : 'Update connection'}
  154. </Button>
  155. </DialogFooter>
  156. </DialogContent>
  157. </Dialog>
  158. )
  159. }