AdvancedSettings.tsx 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. import { type Dispatch, type SetStateAction } from 'react'
  2. import {
  3. Accordion,
  4. AccordionContent,
  5. AccordionItem,
  6. AccordionTrigger,
  7. Badge,
  8. Select,
  9. SelectContent,
  10. SelectItem,
  11. SelectSeparator,
  12. SelectTrigger,
  13. SelectValue,
  14. SheetSection,
  15. } from 'ui'
  16. import { Input } from 'ui-patterns/DataInputs/Input'
  17. import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
  18. import { getExtensionDefaultSchema } from '../IntegrationOverviewTabV2.utils'
  19. import { type ExtensionsSchema, type InstallIntegrationSheetProps } from './InstallIntegrationSheet'
  20. import { extensionsWithRecommendedSchemas } from '@/components/interfaces/Database/Extensions/Extensions.constants'
  21. import { useDatabaseExtensionsQuery } from '@/data/database-extensions/database-extensions-query'
  22. import { useSchemasQuery } from '@/data/database/schemas-query'
  23. import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject'
  24. import { useProtectedSchemas } from '@/hooks/useProtectedSchemas'
  25. type AdvancedSettingsProps = InstallIntegrationSheetProps & {
  26. extensionsSchema: ExtensionsSchema
  27. setExtensionsSchema: Dispatch<SetStateAction<ExtensionsSchema>>
  28. }
  29. export const AdvancedSettings = ({
  30. integration,
  31. extensionsSchema,
  32. setExtensionsSchema,
  33. }: AdvancedSettingsProps) => {
  34. const { data: project } = useSelectedProjectQuery()
  35. const { data: protectedSchemas } = useProtectedSchemas({ excludeSchemas: ['extensions'] })
  36. const { requiredExtensions: requiredExtensionNames } = integration
  37. const involvesExtensions = requiredExtensionNames.length > 0
  38. const { data: extensions = [] } = useDatabaseExtensionsQuery(
  39. { projectRef: project?.ref, connectionString: project?.connectionString },
  40. { enabled: involvesExtensions }
  41. )
  42. const { data: schemas = [] } = useSchemasQuery(
  43. { projectRef: project?.ref, connectionString: project?.connectionString },
  44. { enabled: involvesExtensions }
  45. )
  46. const availableSchemas = schemas.filter(
  47. (schema) => !protectedSchemas.some((protectedSchema) => protectedSchema.name === schema.name)
  48. )
  49. return (
  50. <SheetSection>
  51. <Accordion type="single" collapsible>
  52. <AccordionItem value="advanced-settings" className="border-none">
  53. <AccordionTrigger className="font-normal gap-2 py-0 justify-between text-sm hover:no-underline">
  54. Advanced settings
  55. </AccordionTrigger>
  56. <AccordionContent className="pb-0! pt-3 [&>div]:flex [&>div]:flex-col [&>div]:gap-y-4">
  57. <p className="text-foreground-light">
  58. Select which schemas to install the database extensions under
  59. </p>
  60. {requiredExtensionNames.map((extName) => {
  61. const ext = extensions.find((x) => x.name === extName)
  62. const extMeta = extensionsSchema[extName]
  63. const { schema, value } = extMeta
  64. const recommendedSchema = extensionsWithRecommendedSchemas[extName]
  65. const defaultSchema = getExtensionDefaultSchema(ext)
  66. return (
  67. <FormItemLayout
  68. key={extName}
  69. isReactForm={false}
  70. layout="horizontal"
  71. label={extName}
  72. description={
  73. ext?.installed_version ? (
  74. <>
  75. Installed in <code className="text-code-inline">{ext.schema}</code> schema
  76. </>
  77. ) : defaultSchema ? (
  78. <>
  79. Must be installed in the{' '}
  80. <code className="text-code-inline">{defaultSchema}</code> schema
  81. </>
  82. ) : recommendedSchema ? (
  83. <>
  84. Use the <code className="text-code-inline">{recommendedSchema}</code> schema
  85. for full compatibility with related features
  86. </>
  87. ) : undefined
  88. }
  89. >
  90. <Select
  91. disabled={!!defaultSchema || !!ext?.installed_version}
  92. value={schema}
  93. onValueChange={(schema) =>
  94. setExtensionsSchema((prev) => ({
  95. ...prev,
  96. [extName]: {
  97. schema,
  98. value: schema === 'custom' ? extName : undefined,
  99. },
  100. }))
  101. }
  102. >
  103. <SelectTrigger>
  104. <SelectValue placeholder="Select a schema" />
  105. </SelectTrigger>
  106. <SelectContent>
  107. <SelectItem value="custom">Create a new schema</SelectItem>
  108. <SelectSeparator />
  109. {availableSchemas.map((schema) => {
  110. return (
  111. <SelectItem key={schema.id} value={schema.name}>
  112. {schema.name}
  113. {schema.name === recommendedSchema ? (
  114. <Badge className="ml-2" variant="success">
  115. Recommended
  116. </Badge>
  117. ) : schema.name === 'extensions' ? (
  118. <Badge className="ml-2">Default</Badge>
  119. ) : null}
  120. </SelectItem>
  121. )
  122. })}
  123. {defaultSchema &&
  124. !availableSchemas.some((schema) => schema.name === defaultSchema) ? (
  125. <SelectItem key={defaultSchema} value={defaultSchema}>
  126. {defaultSchema}
  127. <Badge className="ml-2">Default</Badge>
  128. </SelectItem>
  129. ) : null}
  130. </SelectContent>
  131. </Select>
  132. {schema === 'custom' && (
  133. <FormItemLayout
  134. isReactForm={false}
  135. className="mt-2"
  136. label="Provide a name for your new schema"
  137. >
  138. <Input
  139. value={value}
  140. onChange={(e) =>
  141. setExtensionsSchema((prev) => ({
  142. ...prev,
  143. [extName]: {
  144. schema: prev[extName].schema,
  145. value: e.target.value,
  146. },
  147. }))
  148. }
  149. placeholder="Provide a name for your schema"
  150. />
  151. </FormItemLayout>
  152. )}
  153. </FormItemLayout>
  154. )
  155. })}
  156. </AccordionContent>
  157. </AccordionItem>
  158. </Accordion>
  159. </SheetSection>
  160. )
  161. }