mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 09:25:06 +03:00
Chore/refactor db extensions to rq (#19622)
* Init db extensions to RQ * Shift all extensions to RQ * Deprecate extensions meta store * Address comments * Address comment * Address comment * Update apps/studio/components/interfaces/Database/Extensions/EnableExtensionModal.tsx Co-authored-by: Alaister Young <alaister@users.noreply.github.com> * Remove connection string check for entity-types-query and database-triggers-query * Remove connection string checks --------- Co-authored-by: Alaister Young <alaister@users.noreply.github.com>
This commit is contained in:
1 parent
f27bcb808e
commit
04c19a0d62
21 files changed
+438
-239
No files matched your search
@@ -1,9 +1,11 @@
|
||||
import type { PostgresExtension } from '@supabase/postgres-meta'
|
||||
import { useEffect, useState } from 'react'
|
||||
import toast from 'react-hot-toast'
|
||||
import { Button, Form, IconDatabase, IconPlus, Input, Listbox, Modal } from 'ui'
|
||||
|
||||
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import ShimmeringLoader from 'components/ui/ShimmeringLoader'
|
||||
import { useDatabaseExtensionEnableMutation } from 'data/database-extensions/database-extension-enable-mutation'
|
||||
import { useSchemasQuery } from 'data/database/schemas-query'
|
||||
import { useStore } from 'hooks'
|
||||
|
||||
@@ -15,7 +17,7 @@ interface EnableExtensionModalProps {
|
||||
|
||||
const EnableExtensionModal = ({ visible, extension, onCancel }: EnableExtensionModalProps) => {
|
||||
const { project } = useProjectContext()
|
||||
const { ui, meta } = useStore()
|
||||
const { meta } = useStore()
|
||||
const [defaultSchema, setDefaultSchema] = useState()
|
||||
const [fetchingSchemaInfo, setFetchingSchemaInfo] = useState(false)
|
||||
|
||||
@@ -23,6 +25,15 @@ const EnableExtensionModal = ({ visible, extension, onCancel }: EnableExtensionM
|
||||
projectRef: project?.ref,
|
||||
connectionString: project?.connectionString,
|
||||
})
|
||||
const { mutate: enableExtension, isLoading: isEnabling } = useDatabaseExtensionEnableMutation({
|
||||
onSuccess: () => {
|
||||
toast.success(`${extension.name} is on.`)
|
||||
onCancel()
|
||||
},
|
||||
onError: (error) => {
|
||||
toast.error(`Failed to enable ${extension.name}: ${error.message}`)
|
||||
},
|
||||
})
|
||||
|
||||
// [Joshen] Worth checking in with users - whether having this schema selection
|
||||
// might be confusing, and if we should have a tooltip to explain that schemas
|
||||
@@ -58,8 +69,8 @@ const EnableExtensionModal = ({ visible, extension, onCancel }: EnableExtensionM
|
||||
return errors
|
||||
}
|
||||
|
||||
const onSubmit = async (values: any, { setSubmitting }: any) => {
|
||||
setSubmitting(true)
|
||||
const onSubmit = async (values: any) => {
|
||||
if (project === undefined) return console.error('Project is required')
|
||||
|
||||
const schema =
|
||||
defaultSchema !== undefined && defaultSchema !== null
|
||||
@@ -68,45 +79,19 @@ const EnableExtensionModal = ({ visible, extension, onCancel }: EnableExtensionM
|
||||
? values.name
|
||||
: values.schema
|
||||
|
||||
if (!schema.startsWith('pg_')) {
|
||||
const { error: createSchemaError } = await meta.query(`create schema if not exists ${schema}`)
|
||||
if (createSchemaError) {
|
||||
return ui.setNotification({
|
||||
error: createSchemaError,
|
||||
category: 'error',
|
||||
message: `Failed to create schema: ${createSchemaError.message}`,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const { error: createExtensionError } = await meta.extensions.create({
|
||||
enableExtension({
|
||||
projectRef: project.ref,
|
||||
connectionString: project?.connectionString,
|
||||
schema,
|
||||
name: extension.name,
|
||||
version: extension.default_version,
|
||||
cascade: true,
|
||||
createSchema: !schema.startsWith('pg_'),
|
||||
})
|
||||
if (createExtensionError) {
|
||||
ui.setNotification({
|
||||
error: createExtensionError,
|
||||
category: 'error',
|
||||
message: `Failed to toggle ${extension.name.toUpperCase()}: ${
|
||||
createExtensionError.message
|
||||
}`,
|
||||
})
|
||||
} else {
|
||||
ui.setNotification({
|
||||
category: 'success',
|
||||
message: `${extension.name.toUpperCase()} is on.`,
|
||||
})
|
||||
}
|
||||
|
||||
setSubmitting(false)
|
||||
onCancel()
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal
|
||||
closable
|
||||
hideFooter
|
||||
visible={visible}
|
||||
onCancel={onCancel}
|
||||
@@ -126,7 +111,7 @@ const EnableExtensionModal = ({ visible, extension, onCancel }: EnableExtensionM
|
||||
validate={validate}
|
||||
onSubmit={onSubmit}
|
||||
>
|
||||
{({ isSubmitting, values }: any) => {
|
||||
{({ values }: any) => {
|
||||
return (
|
||||
<div className="space-y-4 py-4">
|
||||
<Modal.Content>
|
||||
@@ -188,10 +173,10 @@ const EnableExtensionModal = ({ visible, extension, onCancel }: EnableExtensionM
|
||||
<Modal.Separator />
|
||||
<Modal.Content>
|
||||
<div className="flex items-center justify-end space-x-2">
|
||||
<Button type="default" disabled={isSubmitting} onClick={() => onCancel()}>
|
||||
<Button type="default" disabled={isEnabling} onClick={() => onCancel()}>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button htmlType="submit" disabled={isSubmitting} loading={isSubmitting}>
|
||||
<Button htmlType="submit" disabled={isEnabling} loading={isEnabling}>
|
||||
Enable extension
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
import { PermissionAction } from '@supabase/shared-types/out/constants'
|
||||
import { observer } from 'mobx-react-lite'
|
||||
import { useState } from 'react'
|
||||
|
||||
import ConfirmationModal from 'components/ui/ConfirmationModal'
|
||||
import { useCheckPermissions, useStore } from 'hooks'
|
||||
import { isResponseOk } from 'lib/common/fetch'
|
||||
import Link from 'next/link'
|
||||
import { useState } from 'react'
|
||||
import toast from 'react-hot-toast'
|
||||
import { extensions } from 'shared-data'
|
||||
import { Badge, IconExternalLink, IconLoader, Modal, Toggle } from 'ui'
|
||||
|
||||
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import ConfirmationModal from 'components/ui/ConfirmationModal'
|
||||
import { useDatabaseExtensionDisableMutation } from 'data/database-extensions/database-extension-disable-mutation'
|
||||
import { useCheckPermissions } from 'hooks'
|
||||
import EnableExtensionModal from './EnableExtensionModal'
|
||||
|
||||
interface ExtensionCardProps {
|
||||
@@ -15,13 +17,18 @@ interface ExtensionCardProps {
|
||||
}
|
||||
|
||||
const ExtensionCard = ({ extension }: ExtensionCardProps) => {
|
||||
const { ui, meta } = useStore()
|
||||
|
||||
const { project } = useProjectContext()
|
||||
const isOn = extension.installed_version !== null
|
||||
const [loading, setLoading] = useState(false)
|
||||
const [showConfirmEnableModal, setShowConfirmEnableModal] = useState(false)
|
||||
const siteUrl = process.env.NEXT_PUBLIC_SITE_URL || ''
|
||||
|
||||
const { mutate: disableExtension, isLoading: isDisabling } = useDatabaseExtensionDisableMutation({
|
||||
onSuccess: () => {
|
||||
toast.success(`${extension.name} is off.`)
|
||||
setIsDisableModalOpen(false)
|
||||
},
|
||||
})
|
||||
|
||||
const canUpdateExtensions = useCheckPermissions(
|
||||
PermissionAction.TENANT_SQL_ADMIN_WRITE,
|
||||
'extensions'
|
||||
@@ -36,30 +43,14 @@ const ExtensionCard = ({ extension }: ExtensionCardProps) => {
|
||||
setIsDisableModalOpen(true)
|
||||
}
|
||||
|
||||
async function disableExtension() {
|
||||
try {
|
||||
setLoading(true)
|
||||
const response = await meta.extensions.del(extension.name)
|
||||
if (!isResponseOk(response)) {
|
||||
throw response.error
|
||||
}
|
||||
const onConfirmDisable = () => {
|
||||
if (project === undefined) return console.error('Project is required')
|
||||
|
||||
ui.setNotification({
|
||||
category: 'success',
|
||||
message: `${extension.name.toUpperCase()} is off.`,
|
||||
})
|
||||
setIsDisableModalOpen(false)
|
||||
} catch (error: any) {
|
||||
ui.setNotification({
|
||||
category: 'error',
|
||||
message: `Toggle ${extension.name.toUpperCase()} failed: ${error.message}`,
|
||||
})
|
||||
} finally {
|
||||
// Need to reload them because the delete function
|
||||
// removes the extension from the store
|
||||
meta.extensions.load()
|
||||
setLoading(false)
|
||||
}
|
||||
disableExtension({
|
||||
projectRef: project.ref,
|
||||
connectionString: project.connectionString,
|
||||
id: extension.name,
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -111,7 +102,7 @@ const ExtensionCard = ({ extension }: ExtensionCardProps) => {
|
||||
</Link>
|
||||
) : null}
|
||||
</div>
|
||||
{loading ? (
|
||||
{isDisabling ? (
|
||||
<IconLoader className="animate-spin" size={16} />
|
||||
) : (
|
||||
<Toggle
|
||||
@@ -151,14 +142,13 @@ const ExtensionCard = ({ extension }: ExtensionCardProps) => {
|
||||
visible={isDisableModalOpen}
|
||||
header="Confirm to disable extension"
|
||||
buttonLabel="Disable"
|
||||
buttonLoadingLabel="Disabling"
|
||||
onSelectCancel={() => setIsDisableModalOpen(false)}
|
||||
onSelectConfirm={() => {
|
||||
disableExtension()
|
||||
}}
|
||||
onSelectConfirm={() => onConfirmDisable()}
|
||||
>
|
||||
<Modal.Content>
|
||||
<p className="py-4 text-sm text-foreground-light">
|
||||
Are you sure you want to turn OFF "{extension.name}" extension?
|
||||
Are you sure you want to turn OFF the "{extension.name}" extension?
|
||||
</p>
|
||||
</Modal.Content>
|
||||
</ConfirmationModal>
|
||||
|
||||
@@ -1,29 +1,35 @@
|
||||
import { PermissionAction } from '@supabase/shared-types/out/constants'
|
||||
import { useParams } from 'common'
|
||||
import { isNull, partition } from 'lodash'
|
||||
import { observer } from 'mobx-react-lite'
|
||||
import Link from 'next/link'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { Button, IconAlertCircle, IconExternalLink, IconSearch, Input } from 'ui'
|
||||
|
||||
import { useParams } from 'common/hooks'
|
||||
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import InformationBox from 'components/ui/InformationBox'
|
||||
import NoSearchResults from 'components/ui/NoSearchResults'
|
||||
import { useCheckPermissions, usePermissionsLoaded, useStore } from 'hooks'
|
||||
import ShimmeringLoader from 'components/ui/ShimmeringLoader'
|
||||
import { useDatabaseExtensionsQuery } from 'data/database-extensions/database-extensions-query'
|
||||
import { useCheckPermissions, usePermissionsLoaded } from 'hooks'
|
||||
import ExtensionCard from './ExtensionCard'
|
||||
import { HIDDEN_EXTENSIONS } from './Extensions.constants'
|
||||
import ShimmeringLoader, { GenericSkeletonLoader } from 'components/ui/ShimmeringLoader'
|
||||
import ExtensionCardSkeleton from './ExtensionCardSkeleton'
|
||||
import { HIDDEN_EXTENSIONS } from './Extensions.constants'
|
||||
|
||||
const Extensions = () => {
|
||||
const { meta } = useStore()
|
||||
const { filter } = useParams()
|
||||
const { project } = useProjectContext()
|
||||
const [filterString, setFilterString] = useState<string>('')
|
||||
|
||||
const { data, isLoading } = useDatabaseExtensionsQuery({
|
||||
projectRef: project?.ref,
|
||||
connectionString: project?.connectionString,
|
||||
})
|
||||
|
||||
const extensions =
|
||||
filterString.length === 0
|
||||
? meta.extensions.list()
|
||||
: meta.extensions.list((ext: any) => ext.name.includes(filterString))
|
||||
const isLoading = meta.extensions.isLoading
|
||||
? data ?? []
|
||||
: (data ?? []).filter((ext) => ext.name.includes(filterString))
|
||||
const extensionsWithoutHidden = extensions.filter(
|
||||
(ext: any) => !HIDDEN_EXTENSIONS.includes(ext.name)
|
||||
)
|
||||
|
||||
@@ -17,6 +17,7 @@ import { isResponseOk } from 'lib/common/fetch'
|
||||
import { EXCLUDED_SCHEMAS } from 'lib/constants/schemas'
|
||||
import { SupaResponse } from 'types'
|
||||
import { convertArgumentTypes, convertConfigParams, hasWhitespace } from './Functions.utils'
|
||||
import { useDatabaseExtensionsQuery } from 'data/database-extensions/database-extensions-query'
|
||||
|
||||
// [Refactor] Remove local state, just use the Form component
|
||||
|
||||
@@ -755,13 +756,15 @@ const SelectSchema = observer(({}) => {
|
||||
})
|
||||
|
||||
const SelectLanguage = observer(({}) => {
|
||||
const { meta } = useStore()
|
||||
const _localState = useContext(CreateFunctionContext)
|
||||
const { project } = useProjectContext()
|
||||
|
||||
const [enabledExtensions] = partition(
|
||||
meta.extensions.list(),
|
||||
(ext: any) => !isNull(ext.installed_version)
|
||||
)
|
||||
const { data } = useDatabaseExtensionsQuery({
|
||||
projectRef: project?.ref,
|
||||
connectionString: project?.connectionString,
|
||||
})
|
||||
|
||||
const [enabledExtensions] = partition(data ?? [], (ext: any) => !isNull(ext.installed_version))
|
||||
|
||||
return (
|
||||
<Listbox
|
||||
|
||||
@@ -6,8 +6,8 @@ import { Button, IconExternalLink } from 'ui'
|
||||
|
||||
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import { GenericSkeletonLoader } from 'components/ui/ShimmeringLoader'
|
||||
import { useDatabaseExtensionsQuery } from 'data/database-extensions/database-extensions-query'
|
||||
import { FDW, useFDWsQuery } from 'data/fdw/fdws-query'
|
||||
import { useStore } from 'hooks'
|
||||
import DeleteWrapperModal from './DeleteWrapperModal'
|
||||
import WrapperRow from './WrapperRow'
|
||||
import { WRAPPERS } from './Wrappers.constants'
|
||||
@@ -15,12 +15,17 @@ import WrappersDisabledState from './WrappersDisabledState'
|
||||
import WrappersDropdown from './WrappersDropdown'
|
||||
|
||||
const Wrappers = () => {
|
||||
const { meta } = useStore()
|
||||
const { project } = useProjectContext()
|
||||
const { data, isLoading } = useFDWsQuery({
|
||||
projectRef: project?.ref,
|
||||
connectionString: project?.connectionString,
|
||||
})
|
||||
const { data: exts, isLoading: isLoadingExtensions } = useDatabaseExtensionsQuery({
|
||||
projectRef: project?.ref,
|
||||
connectionString: project?.connectionString,
|
||||
})
|
||||
const wrappersExtension = (exts ?? []).find((ext) => ext.name === 'wrappers')
|
||||
const vaultExtension = (exts ?? []).find((ext) => ext.name === 'supabase_vault')
|
||||
|
||||
const [open, setOpen] = useState<string>('')
|
||||
const [selectedWrapperToDelete, setSelectedWrapperToDelete] = useState<FDW>()
|
||||
@@ -28,10 +33,6 @@ const Wrappers = () => {
|
||||
const wrappers = data?.result ?? []
|
||||
const groupedWrappers = groupBy(wrappers, 'handler')
|
||||
|
||||
const wrappersExtension = meta.extensions.byId('wrappers')
|
||||
const vaultExtension = meta.extensions.byId('supabase_vault')
|
||||
const isLoadingExtensions = meta.extensions.isLoading
|
||||
|
||||
const isWrappersEnabled =
|
||||
wrappersExtension !== undefined &&
|
||||
wrappersExtension.installed_version !== null &&
|
||||
|
||||
@@ -1,21 +1,30 @@
|
||||
import * as Tooltip from '@radix-ui/react-tooltip'
|
||||
import { PermissionAction } from '@supabase/shared-types/out/constants'
|
||||
import { useParams } from 'common'
|
||||
import { observer } from 'mobx-react-lite'
|
||||
import { useTheme } from 'next-themes'
|
||||
import Link from 'next/link'
|
||||
import { useState } from 'react'
|
||||
import toast from 'react-hot-toast'
|
||||
import { Button, IconExternalLink } from 'ui'
|
||||
|
||||
import { useTheme } from 'next-themes'
|
||||
import { useCheckPermissions, useStore } from 'hooks'
|
||||
import { useParams } from 'common/hooks'
|
||||
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import { useDatabaseExtensionEnableMutation } from 'data/database-extensions/database-extension-enable-mutation'
|
||||
import { useDatabaseExtensionsQuery } from 'data/database-extensions/database-extensions-query'
|
||||
import { useCheckPermissions } from 'hooks'
|
||||
import { BASE_PATH } from 'lib/constants'
|
||||
|
||||
const WrappersDisabledState = () => {
|
||||
const { ui, meta } = useStore()
|
||||
const { ref } = useParams()
|
||||
const { resolvedTheme } = useTheme()
|
||||
const wrappersExtension = meta.extensions.byId('wrappers')
|
||||
const vaultExtension = meta.extensions.byId('supabase_vault')
|
||||
const { project } = useProjectContext()
|
||||
|
||||
const { data } = useDatabaseExtensionsQuery({
|
||||
projectRef: project?.ref,
|
||||
connectionString: project?.connectionString,
|
||||
})
|
||||
const wrappersExtension = (data ?? []).find((ext) => ext.name === 'wrappers')
|
||||
const vaultExtension = (data ?? []).find((ext) => ext.name === 'supabase_vault')
|
||||
const isNotAvailable = wrappersExtension === undefined || vaultExtension === undefined
|
||||
|
||||
const [isEnabling, setIsEnabling] = useState<boolean>(false)
|
||||
@@ -24,44 +33,43 @@ const WrappersDisabledState = () => {
|
||||
'extensions'
|
||||
)
|
||||
|
||||
const { mutateAsync: enableExtension } = useDatabaseExtensionEnableMutation({ onError: () => {} })
|
||||
|
||||
const onEnableWrappers = async () => {
|
||||
if (wrappersExtension === undefined || vaultExtension === undefined) return
|
||||
setIsEnabling(true)
|
||||
if (project === undefined) return console.error('Project is required')
|
||||
|
||||
const requiredExtensions = await Promise.all([
|
||||
await meta.extensions.create({
|
||||
schema: wrappersExtension.schema ?? 'extensions',
|
||||
name: wrappersExtension.name,
|
||||
version: wrappersExtension.default_version,
|
||||
cascade: true,
|
||||
}),
|
||||
await meta.extensions.create({
|
||||
schema: vaultExtension.schema ?? 'vault',
|
||||
name: vaultExtension.name,
|
||||
version: vaultExtension.default_version,
|
||||
cascade: true,
|
||||
}),
|
||||
])
|
||||
const errors = requiredExtensions.filter(
|
||||
(res) => res.error && !res.error.message.includes('already exists')
|
||||
)
|
||||
let hasError = false
|
||||
|
||||
if (errors.length > 0) {
|
||||
ui.setNotification({
|
||||
error: errors,
|
||||
category: 'error',
|
||||
message: `Failed to enable Wrappers for your project: ${errors
|
||||
.map((x) => x.message)
|
||||
.join(', ')}`,
|
||||
})
|
||||
} else {
|
||||
ui.setNotification({
|
||||
category: 'success',
|
||||
message: 'Wrappers is now enabled for your project!',
|
||||
})
|
||||
try {
|
||||
setIsEnabling(true)
|
||||
await Promise.all([
|
||||
enableExtension({
|
||||
projectRef: project.ref,
|
||||
connectionString: project.connectionString,
|
||||
schema: wrappersExtension.schema ?? 'extensions',
|
||||
name: wrappersExtension.name,
|
||||
version: wrappersExtension.default_version,
|
||||
cascade: true,
|
||||
}),
|
||||
enableExtension({
|
||||
projectRef: project.ref,
|
||||
connectionString: project.connectionString,
|
||||
schema: vaultExtension.schema ?? 'vault',
|
||||
name: vaultExtension.name,
|
||||
version: vaultExtension.default_version,
|
||||
cascade: true,
|
||||
}),
|
||||
])
|
||||
} catch (error: any) {
|
||||
if (!error.message.includes('already exists')) {
|
||||
hasError = true
|
||||
toast.error(`Failed to enable Wrappers: ${error.message}`)
|
||||
}
|
||||
} finally {
|
||||
setIsEnabling(false)
|
||||
if (!hasError) toast.success('Wrappers is now enabled!')
|
||||
}
|
||||
|
||||
setIsEnabling(false)
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,27 +1,48 @@
|
||||
import * as Tooltip from '@radix-ui/react-tooltip'
|
||||
import { PermissionAction } from '@supabase/shared-types/out/constants'
|
||||
import { useParams } from 'common'
|
||||
import { useTheme } from 'next-themes'
|
||||
import { observer } from 'mobx-react-lite'
|
||||
import { useTheme } from 'next-themes'
|
||||
import Link from 'next/link'
|
||||
import { useState } from 'react'
|
||||
import toast from 'react-hot-toast'
|
||||
import { Button, IconExternalLink } from 'ui'
|
||||
|
||||
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import { useDatabaseExtensionEnableMutation } from 'data/database-extensions/database-extension-enable-mutation'
|
||||
import { useDatabaseExtensionsQuery } from 'data/database-extensions/database-extensions-query'
|
||||
import { useCheckPermissions, useStore } from 'hooks'
|
||||
import { BASE_PATH } from 'lib/constants'
|
||||
|
||||
const VaultToggle = () => {
|
||||
const { meta, ui } = useStore()
|
||||
const { ref } = useParams()
|
||||
const { meta, ui } = useStore()
|
||||
const { resolvedTheme } = useTheme()
|
||||
const { project } = useProjectContext()
|
||||
const [isEnabling, setIsEnabling] = useState(false)
|
||||
const canToggleVault = useCheckPermissions(PermissionAction.TENANT_SQL_ADMIN_WRITE, 'extensions')
|
||||
|
||||
const vaultExtension = meta.extensions.byId('supabase_vault')
|
||||
const { data } = useDatabaseExtensionsQuery({
|
||||
projectRef: project?.ref,
|
||||
connectionString: project?.connectionString,
|
||||
})
|
||||
const vaultExtension = (data ?? []).find((ext) => ext.name === 'supabase_vault')
|
||||
const isNotAvailable = vaultExtension === undefined
|
||||
|
||||
const { mutate: enableExtension } = useDatabaseExtensionEnableMutation({
|
||||
onSuccess: () => {
|
||||
toast.success(`Vault is now enabled for your project!`)
|
||||
},
|
||||
onError: (error) => {
|
||||
toast.error(`Failed to enable Vault for your project: ${error.message}`)
|
||||
setIsEnabling(false)
|
||||
},
|
||||
})
|
||||
|
||||
const onEnableVault = async () => {
|
||||
if (vaultExtension === undefined) return
|
||||
if (project === undefined) return console.error('Project is required')
|
||||
|
||||
setIsEnabling(true)
|
||||
|
||||
const { error: createSchemaError } = await meta.query(
|
||||
@@ -36,25 +57,14 @@ const VaultToggle = () => {
|
||||
})
|
||||
}
|
||||
|
||||
const { error: createExtensionError } = await meta.extensions.create({
|
||||
enableExtension({
|
||||
projectRef: project.ref,
|
||||
connectionString: project.connectionString,
|
||||
schema: vaultExtension.schema ?? 'vault',
|
||||
name: vaultExtension.name,
|
||||
version: vaultExtension.default_version,
|
||||
cascade: true,
|
||||
})
|
||||
if (createExtensionError) {
|
||||
ui.setNotification({
|
||||
error: createExtensionError,
|
||||
category: 'error',
|
||||
message: `Failed to enable Vault for your project: ${createExtensionError.message}`,
|
||||
})
|
||||
setIsEnabling(false)
|
||||
} else {
|
||||
ui.setNotification({
|
||||
category: 'success',
|
||||
message: 'Vault is now enabled for your project!',
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
@@ -3,6 +3,7 @@ import { useRouter } from 'next/router'
|
||||
import { PropsWithChildren, useEffect } from 'react'
|
||||
|
||||
import ProductMenu from 'components/ui/ProductMenu'
|
||||
import { useDatabaseExtensionsQuery } from 'data/database-extensions/database-extensions-query'
|
||||
import { useSelectedProject, useStore, withAuth } from 'hooks'
|
||||
import ProjectLayout from '../'
|
||||
import { generateDatabaseMenu } from './DatabaseMenu.utils'
|
||||
@@ -18,15 +19,18 @@ const DatabaseLayout = ({ children }: PropsWithChildren<DatabaseLayoutProps>) =>
|
||||
const router = useRouter()
|
||||
const page = router.pathname.split('/')[4]
|
||||
|
||||
const vaultExtension = meta.extensions.byId('supabase_vault')
|
||||
const { data } = useDatabaseExtensionsQuery({
|
||||
projectRef: project?.ref,
|
||||
connectionString: project?.connectionString,
|
||||
})
|
||||
const vaultExtension = (data ?? []).find((ext) => ext.name === 'supabase_vault')
|
||||
const isVaultEnabled = vaultExtension !== undefined && vaultExtension.installed_version !== null
|
||||
const pgNetExtensionExists = meta.extensions.byId('pg_net') !== undefined
|
||||
const pgNetExtensionExists = (data ?? []).find((ext) => ext.name === 'pg_net') !== undefined
|
||||
|
||||
useEffect(() => {
|
||||
if (ui.selectedProjectRef) {
|
||||
meta.roles.load()
|
||||
meta.triggers.load()
|
||||
meta.extensions.load()
|
||||
meta.publications.load()
|
||||
}
|
||||
}, [ui.selectedProjectRef])
|
||||
|
||||
@@ -1,19 +1,12 @@
|
||||
import {
|
||||
useFlag,
|
||||
useIsFeatureEnabled,
|
||||
useSelectedOrganization,
|
||||
useSelectedProject,
|
||||
useStore,
|
||||
withAuth,
|
||||
} from 'hooks'
|
||||
import { useIsFeatureEnabled, useSelectedOrganization, useSelectedProject, withAuth } from 'hooks'
|
||||
import { observer } from 'mobx-react-lite'
|
||||
import { useRouter } from 'next/router'
|
||||
import { PropsWithChildren, useEffect } from 'react'
|
||||
import { PropsWithChildren } from 'react'
|
||||
import { generateSettingsMenu } from './SettingsMenu.utils'
|
||||
|
||||
import { useParams } from 'common'
|
||||
import ProductMenu from 'components/ui/ProductMenu'
|
||||
import ProjectLayout from '..'
|
||||
import { useParams } from 'common'
|
||||
|
||||
interface SettingsLayoutProps {
|
||||
title?: string
|
||||
@@ -22,7 +15,6 @@ interface SettingsLayoutProps {
|
||||
const SettingsLayout = ({ title, children }: PropsWithChildren<SettingsLayoutProps>) => {
|
||||
const router = useRouter()
|
||||
const { ref } = useParams()
|
||||
const { ui, meta } = useStore()
|
||||
const project = useSelectedProject()
|
||||
const organization = useSelectedOrganization()
|
||||
|
||||
@@ -51,12 +43,6 @@ const SettingsLayout = ({ title, children }: PropsWithChildren<SettingsLayoutPro
|
||||
invoices: invoicesEnabled,
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
if (ui.selectedProjectRef) {
|
||||
meta.extensions.load()
|
||||
}
|
||||
}, [ui.selectedProjectRef])
|
||||
|
||||
return (
|
||||
<ProjectLayout
|
||||
title={title || 'Settings'}
|
||||
|
||||
@@ -3,24 +3,29 @@ import { observer } from 'mobx-react-lite'
|
||||
import { PropsWithChildren, useEffect, useMemo } from 'react'
|
||||
|
||||
import NoPermission from 'components/ui/NoPermission'
|
||||
import { useCheckPermissions, usePermissionsLoaded, useStore } from 'hooks'
|
||||
import { useDatabaseExtensionsQuery } from 'data/database-extensions/database-extensions-query'
|
||||
import { useCheckPermissions, usePermissionsLoaded, useSelectedProject, useStore } from 'hooks'
|
||||
import { ProjectLayoutWithAuth } from '../'
|
||||
import TableEditorMenu from './TableEditorMenu'
|
||||
|
||||
const TableEditorLayout = ({ children }: PropsWithChildren<{}>) => {
|
||||
const { vault, meta, ui } = useStore()
|
||||
const project = useSelectedProject()
|
||||
|
||||
const canReadTables = useCheckPermissions(PermissionAction.TENANT_SQL_ADMIN_READ, 'tables')
|
||||
const isPermissionsLoaded = usePermissionsLoaded()
|
||||
|
||||
const vaultExtension = meta.extensions.byId('supabase_vault')
|
||||
const { data } = useDatabaseExtensionsQuery({
|
||||
projectRef: project?.ref,
|
||||
connectionString: project?.connectionString,
|
||||
})
|
||||
const vaultExtension = (data ?? []).find((ext) => ext.name === 'supabase_vault')
|
||||
const isVaultEnabled = vaultExtension !== undefined && vaultExtension.installed_version !== null
|
||||
|
||||
useEffect(() => {
|
||||
if (ui.selectedProjectRef) {
|
||||
meta.policies.load()
|
||||
meta.publications.load()
|
||||
meta.extensions.load()
|
||||
}
|
||||
}, [ui.selectedProjectRef])
|
||||
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
import { useMutation, UseMutationOptions, useQueryClient } from '@tanstack/react-query'
|
||||
import { toast } from 'react-hot-toast'
|
||||
|
||||
import { del } from 'data/fetchers'
|
||||
import { ResponseError } from 'types'
|
||||
import { databaseExtensionsKeys } from './keys'
|
||||
|
||||
export type DatabaseExtensionDisableVariables = {
|
||||
projectRef: string
|
||||
connectionString?: string
|
||||
id: string
|
||||
}
|
||||
|
||||
export async function disableDatabaseExtension({
|
||||
projectRef,
|
||||
connectionString,
|
||||
id,
|
||||
}: DatabaseExtensionDisableVariables) {
|
||||
let headers = new Headers()
|
||||
if (connectionString) headers.set('x-connection-encrypted', connectionString)
|
||||
|
||||
const { data, error } = await del('/platform/pg-meta/{ref}/extensions', {
|
||||
params: {
|
||||
header: { 'x-connection-encrypted': connectionString! },
|
||||
path: { ref: projectRef },
|
||||
query: { id },
|
||||
},
|
||||
headers,
|
||||
})
|
||||
|
||||
if (error) throw error
|
||||
return data
|
||||
}
|
||||
|
||||
type DatabaseExtensionDisableData = Awaited<ReturnType<typeof disableDatabaseExtension>>
|
||||
|
||||
export const useDatabaseExtensionDisableMutation = ({
|
||||
onSuccess,
|
||||
onError,
|
||||
...options
|
||||
}: Omit<
|
||||
UseMutationOptions<
|
||||
DatabaseExtensionDisableData,
|
||||
ResponseError,
|
||||
DatabaseExtensionDisableVariables
|
||||
>,
|
||||
'mutationFn'
|
||||
> = {}) => {
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
return useMutation<
|
||||
DatabaseExtensionDisableData,
|
||||
ResponseError,
|
||||
DatabaseExtensionDisableVariables
|
||||
>((vars) => disableDatabaseExtension(vars), {
|
||||
async onSuccess(data, variables, context) {
|
||||
const { projectRef } = variables
|
||||
await queryClient.invalidateQueries(databaseExtensionsKeys.list(projectRef))
|
||||
await onSuccess?.(data, variables, context)
|
||||
},
|
||||
async onError(data, variables, context) {
|
||||
if (onError === undefined) {
|
||||
toast.error(`Failed to disable database extension: ${data.message}`)
|
||||
} else {
|
||||
onError(data, variables, context)
|
||||
}
|
||||
},
|
||||
...options,
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
import { useMutation, UseMutationOptions, useQueryClient } from '@tanstack/react-query'
|
||||
import { toast } from 'react-hot-toast'
|
||||
|
||||
import { post } from 'data/fetchers'
|
||||
import { ResponseError } from 'types'
|
||||
import { databaseExtensionsKeys } from './keys'
|
||||
import { executeSql } from 'data/sql/execute-sql-query'
|
||||
|
||||
export type DatabaseExtensionEnableVariables = {
|
||||
projectRef: string
|
||||
connectionString?: string
|
||||
schema: string
|
||||
name: string
|
||||
version: string
|
||||
cascade?: boolean
|
||||
createSchema?: boolean
|
||||
}
|
||||
|
||||
export async function enableDatabaseExtension({
|
||||
projectRef,
|
||||
connectionString,
|
||||
schema,
|
||||
name,
|
||||
version,
|
||||
cascade = false,
|
||||
createSchema = false,
|
||||
}: DatabaseExtensionEnableVariables) {
|
||||
let headers = new Headers()
|
||||
if (connectionString) headers.set('x-connection-encrypted', connectionString)
|
||||
|
||||
if (createSchema) {
|
||||
try {
|
||||
await executeSql({
|
||||
projectRef,
|
||||
connectionString,
|
||||
sql: `create schema if not exists ${schema}`,
|
||||
})
|
||||
} catch (error) {
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
const { data, error } = await post('/platform/pg-meta/{ref}/extensions', {
|
||||
params: {
|
||||
header: { 'x-connection-encrypted': connectionString! },
|
||||
path: { ref: projectRef },
|
||||
},
|
||||
body: { schema, name, version, cascade },
|
||||
headers,
|
||||
})
|
||||
|
||||
if (error) throw error
|
||||
return data
|
||||
}
|
||||
|
||||
type DatabaseExtensionEnableData = Awaited<ReturnType<typeof enableDatabaseExtension>>
|
||||
|
||||
export const useDatabaseExtensionEnableMutation = ({
|
||||
onSuccess,
|
||||
onError,
|
||||
...options
|
||||
}: Omit<
|
||||
UseMutationOptions<DatabaseExtensionEnableData, ResponseError, DatabaseExtensionEnableVariables>,
|
||||
'mutationFn'
|
||||
> = {}) => {
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
return useMutation<DatabaseExtensionEnableData, ResponseError, DatabaseExtensionEnableVariables>(
|
||||
(vars) => enableDatabaseExtension(vars),
|
||||
{
|
||||
async onSuccess(data, variables, context) {
|
||||
const { projectRef } = variables
|
||||
await queryClient.invalidateQueries(databaseExtensionsKeys.list(projectRef))
|
||||
await onSuccess?.(data, variables, context)
|
||||
},
|
||||
async onError(data, variables, context) {
|
||||
if (onError === undefined) {
|
||||
toast.error(`Failed to enable database extension: ${data.message}`)
|
||||
} else {
|
||||
onError(data, variables, context)
|
||||
}
|
||||
},
|
||||
...options,
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
import { UseQueryOptions, useQuery, useQueryClient } from '@tanstack/react-query'
|
||||
import { get } from 'data/fetchers'
|
||||
import { useCallback } from 'react'
|
||||
import { ResponseError } from 'types'
|
||||
import { databaseExtensionsKeys } from './keys'
|
||||
|
||||
export type DatabaseExtensionsVariables = {
|
||||
projectRef?: string
|
||||
connectionString?: string
|
||||
}
|
||||
|
||||
export async function getDatabaseExtensions(
|
||||
{ projectRef, connectionString }: DatabaseExtensionsVariables,
|
||||
signal?: AbortSignal
|
||||
) {
|
||||
if (!projectRef) throw new Error('projectRef is required')
|
||||
|
||||
let headers = new Headers()
|
||||
if (connectionString) headers.set('x-connection-encrypted', connectionString)
|
||||
|
||||
const { data, error } = await get('/platform/pg-meta/{ref}/extensions', {
|
||||
params: {
|
||||
header: {
|
||||
'x-connection-encrypted': connectionString!,
|
||||
},
|
||||
path: {
|
||||
ref: projectRef,
|
||||
},
|
||||
},
|
||||
headers,
|
||||
signal,
|
||||
})
|
||||
|
||||
if (error) throw error
|
||||
return data
|
||||
}
|
||||
|
||||
export type DatabaseExtensionsData = Awaited<ReturnType<typeof getDatabaseExtensions>>
|
||||
export type DatabaseExtensionsError = ResponseError
|
||||
|
||||
export const useDatabaseExtensionsQuery = <TData = DatabaseExtensionsData>(
|
||||
{ projectRef, connectionString }: DatabaseExtensionsVariables,
|
||||
{
|
||||
enabled = true,
|
||||
...options
|
||||
}: UseQueryOptions<DatabaseExtensionsData, DatabaseExtensionsError, TData> = {}
|
||||
) =>
|
||||
useQuery<DatabaseExtensionsData, DatabaseExtensionsError, TData>(
|
||||
databaseExtensionsKeys.list(projectRef),
|
||||
({ signal }) => getDatabaseExtensions({ projectRef, connectionString }, signal),
|
||||
{
|
||||
enabled: enabled && typeof projectRef !== 'undefined',
|
||||
...options,
|
||||
}
|
||||
)
|
||||
|
||||
export const useDatabaseExtensionsPrefetch = ({ projectRef }: DatabaseExtensionsVariables) => {
|
||||
const client = useQueryClient()
|
||||
|
||||
return useCallback(() => {
|
||||
if (projectRef) {
|
||||
client.prefetchQuery(databaseExtensionsKeys.list(projectRef), ({ signal }) =>
|
||||
getDatabaseExtensions({ projectRef }, signal)
|
||||
)
|
||||
}
|
||||
}, [projectRef])
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
export const databaseExtensionsKeys = {
|
||||
list: (projectRef: string | undefined) =>
|
||||
['projects', projectRef, 'database-extensions'] as const,
|
||||
}
|
||||
@@ -51,8 +51,7 @@ export const useDatabaseHooks = <TData = DatabaseTriggersData>(
|
||||
(trigger.schema !== 'net' || trigger.function_args.length === 0)
|
||||
)
|
||||
},
|
||||
enabled:
|
||||
enabled && typeof projectRef !== 'undefined' && typeof connectionString !== 'undefined',
|
||||
enabled: enabled && typeof projectRef !== 'undefined',
|
||||
...options,
|
||||
}
|
||||
)
|
||||
@@ -68,8 +67,7 @@ export const useDatabaseTriggers = <TData = DatabaseTriggersData>(
|
||||
databaseTriggerKeys.list(projectRef),
|
||||
({ signal }) => getDatabaseTriggers({ projectRef, connectionString }, signal),
|
||||
{
|
||||
enabled:
|
||||
enabled && typeof projectRef !== 'undefined' && typeof connectionString !== 'undefined',
|
||||
enabled: enabled && typeof projectRef !== 'undefined',
|
||||
...options,
|
||||
}
|
||||
)
|
||||
|
||||
@@ -125,8 +125,7 @@ export const useEntityTypesQuery = <TData = EntityTypesData>(
|
||||
signal
|
||||
),
|
||||
{
|
||||
enabled:
|
||||
enabled && typeof projectRef !== 'undefined' && typeof connectionString !== 'undefined',
|
||||
enabled: enabled && typeof projectRef !== 'undefined',
|
||||
getNextPageParam(lastPage, pages) {
|
||||
const page = pages.length
|
||||
const currentTotalCount = page * limit
|
||||
|
||||
@@ -3,29 +3,33 @@ import { createGraphiQLFetcher, Fetcher } from '@graphiql/toolkit'
|
||||
import { useParams } from 'common'
|
||||
import { observer } from 'mobx-react-lite'
|
||||
import { useTheme } from 'next-themes'
|
||||
import { useEffect, useMemo } from 'react'
|
||||
import { useMemo } from 'react'
|
||||
|
||||
import ExtensionCard from 'components/interfaces/Database/Extensions/ExtensionCard'
|
||||
import GraphiQL from 'components/interfaces/GraphQL/GraphiQL'
|
||||
import { DocsLayout } from 'components/layouts'
|
||||
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import Connecting from 'components/ui/Loading/Loading'
|
||||
import { useSessionAccessTokenQuery } from 'data/auth/session-access-token-query'
|
||||
import { useProjectApiQuery } from 'data/config/project-api-query'
|
||||
import { useProjectPostgrestConfigQuery } from 'data/config/project-postgrest-config-query'
|
||||
import { useStore } from 'hooks'
|
||||
import { useDatabaseExtensionsQuery } from 'data/database-extensions/database-extensions-query'
|
||||
import { API_URL, IS_PLATFORM } from 'lib/constants'
|
||||
import { getRoleImpersonationJWT } from 'lib/role-impersonation'
|
||||
import { useGetImpersonatedRole } from 'state/role-impersonation-state'
|
||||
import { NextPageWithLayout } from 'types'
|
||||
|
||||
const GraphiQLPage: NextPageWithLayout = () => {
|
||||
const { ui, meta } = useStore()
|
||||
const { resolvedTheme } = useTheme()
|
||||
const { ref: projectRef } = useParams()
|
||||
const { project } = useProjectContext()
|
||||
const currentTheme = resolvedTheme?.includes('dark') ? 'dark' : 'light'
|
||||
|
||||
const isExtensionsLoading = meta.extensions.isLoading
|
||||
const pgGraphqlExtension = meta.extensions.byId('pg_graphql')
|
||||
const { data, isLoading: isExtensionsLoading } = useDatabaseExtensionsQuery({
|
||||
projectRef: project?.ref,
|
||||
connectionString: project?.connectionString,
|
||||
})
|
||||
const pgGraphqlExtension = (data ?? []).find((ext) => ext.name === 'pg_graphql')
|
||||
|
||||
const { data: accessToken } = useSessionAccessTokenQuery({ enabled: IS_PLATFORM })
|
||||
const { data: settings, isFetched } = useProjectApiQuery({ projectRef })
|
||||
@@ -38,13 +42,6 @@ const GraphiQLPage: NextPageWithLayout = () => {
|
||||
const { data: config } = useProjectPostgrestConfigQuery({ projectRef })
|
||||
const jwtSecret = config?.jwt_secret
|
||||
|
||||
useEffect(() => {
|
||||
if (ui.selectedProjectRef) {
|
||||
// Schemas may be needed when enabling the GraphQL extension
|
||||
meta.extensions.load()
|
||||
}
|
||||
}, [ui.selectedProjectRef])
|
||||
|
||||
const getImpersonatedRole = useGetImpersonatedRole()
|
||||
|
||||
const fetcher = useMemo(() => {
|
||||
|
||||
@@ -1,21 +1,29 @@
|
||||
import { useEffect } from 'react'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useParams } from 'common'
|
||||
import { observer } from 'mobx-react-lite'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useEffect } from 'react'
|
||||
import { Tabs } from 'ui'
|
||||
|
||||
import { useStore } from 'hooks'
|
||||
import { useParams } from 'common/hooks'
|
||||
import { NextPageWithLayout } from 'types'
|
||||
import { EncryptionKeysManagement, VaultToggle } from 'components/interfaces/Settings/Vault'
|
||||
import { SettingsLayout } from 'components/layouts'
|
||||
import { VaultToggle, EncryptionKeysManagement } from 'components/interfaces/Settings/Vault'
|
||||
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import { FormHeader } from 'components/ui/Forms'
|
||||
import { useDatabaseExtensionsQuery } from 'data/database-extensions/database-extensions-query'
|
||||
import { useStore } from 'hooks'
|
||||
import { NextPageWithLayout } from 'types'
|
||||
|
||||
const VaultSettingsSecrets: NextPageWithLayout = () => {
|
||||
const router = useRouter()
|
||||
const { meta, vault } = useStore()
|
||||
const { ref } = useParams()
|
||||
const { vault } = useStore()
|
||||
const { project } = useProjectContext()
|
||||
|
||||
const vaultExtension = meta.extensions.byId('supabase_vault')
|
||||
const { data } = useDatabaseExtensionsQuery({
|
||||
projectRef: project?.ref,
|
||||
connectionString: project?.connectionString,
|
||||
})
|
||||
|
||||
const vaultExtension = (data ?? []).find((ext) => ext.name === 'supabase_vault')
|
||||
const isEnabled = vaultExtension !== undefined && vaultExtension.installed_version !== null
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -1,23 +1,30 @@
|
||||
import { useEffect } from 'react'
|
||||
import { useRouter } from 'next/router'
|
||||
import { observer } from 'mobx-react-lite'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useEffect } from 'react'
|
||||
import { Tabs } from 'ui'
|
||||
|
||||
import { useStore } from 'hooks'
|
||||
import { useParams } from 'common/hooks'
|
||||
import { NextPageWithLayout } from 'types'
|
||||
import { SecretsManagement, VaultToggle } from 'components/interfaces/Settings/Vault'
|
||||
import { SettingsLayout } from 'components/layouts'
|
||||
import { VaultToggle, SecretsManagement } from 'components/interfaces/Settings/Vault'
|
||||
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import { FormHeader } from 'components/ui/Forms'
|
||||
import ShimmeringLoader from 'components/ui/ShimmeringLoader'
|
||||
import { useDatabaseExtensionsQuery } from 'data/database-extensions/database-extensions-query'
|
||||
import { useStore } from 'hooks'
|
||||
import { NextPageWithLayout } from 'types'
|
||||
|
||||
const VaultSettingsSecrets: NextPageWithLayout = () => {
|
||||
const router = useRouter()
|
||||
const { meta, vault } = useStore()
|
||||
const { vault } = useStore()
|
||||
const { ref } = useParams()
|
||||
const { project } = useProjectContext()
|
||||
|
||||
const vaultExtension = meta.extensions.byId('supabase_vault')
|
||||
const isLoading = meta.extensions.isLoading
|
||||
const { data, isLoading } = useDatabaseExtensionsQuery({
|
||||
projectRef: project?.ref,
|
||||
connectionString: project?.connectionString,
|
||||
})
|
||||
|
||||
const vaultExtension = (data ?? []).find((ext) => ext.name === 'supabase_vault')
|
||||
const isEnabled = vaultExtension !== undefined && vaultExtension.installed_version !== null
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
import PostgresMetaInterface from '../common/PostgresMetaInterface'
|
||||
import type { PostgresColumn } from '@supabase/postgres-meta'
|
||||
import { IRootStore } from '../RootStore'
|
||||
|
||||
export default class ExtensionsStore extends PostgresMetaInterface<PostgresColumn> {
|
||||
constructor(
|
||||
rootStore: IRootStore,
|
||||
dataUrl: string,
|
||||
headers?: {
|
||||
[prop: string]: any
|
||||
},
|
||||
options?: { identifier: string }
|
||||
) {
|
||||
super(rootStore, dataUrl, headers, options)
|
||||
}
|
||||
|
||||
// loadBySchema is not supported in this store
|
||||
async loadBySchema(schema: string) {
|
||||
return []
|
||||
}
|
||||
}
|
||||
@@ -38,7 +38,6 @@ import { getQueryClient } from 'data/query-client'
|
||||
import { tableKeys } from 'data/tables/keys'
|
||||
import { getTable } from 'data/tables/table-query'
|
||||
import { getTables } from 'data/tables/tables-query'
|
||||
import ExtensionsStore from './ExtensionsStore'
|
||||
import ForeignTableStore, { IForeignTableStore } from './ForeignTableStore'
|
||||
import FunctionsStore from './FunctionsStore'
|
||||
import MaterializedViewStore, { IMaterializedViewStore } from './MaterializedViewStore'
|
||||
@@ -63,7 +62,6 @@ export interface IMetaStore {
|
||||
policies: IPostgresMetaInterface<any>
|
||||
triggers: IPostgresMetaInterface<any>
|
||||
functions: IPostgresMetaInterface<any>
|
||||
extensions: IPostgresMetaInterface<any>
|
||||
publications: IPostgresMetaInterface<any>
|
||||
|
||||
projectRef?: string
|
||||
@@ -153,7 +151,6 @@ export default class MetaStore implements IMetaStore {
|
||||
policies: PoliciesStore
|
||||
triggers: TriggersStore
|
||||
functions: FunctionsStore
|
||||
extensions: ExtensionsStore
|
||||
publications: PublicationStore
|
||||
|
||||
projectRef?: string
|
||||
@@ -195,14 +192,6 @@ export default class MetaStore implements IMetaStore {
|
||||
this.policies = new PoliciesStore(this.rootStore, `${this.baseUrl}/policies`, this.headers)
|
||||
this.triggers = new TriggersStore(this.rootStore, `${this.baseUrl}/triggers`, this.headers)
|
||||
this.functions = new FunctionsStore(this.rootStore, `${this.baseUrl}/functions`, this.headers)
|
||||
this.extensions = new ExtensionsStore(
|
||||
this.rootStore,
|
||||
`${this.baseUrl}/extensions`,
|
||||
this.headers,
|
||||
{
|
||||
identifier: 'name',
|
||||
}
|
||||
)
|
||||
this.publications = new PublicationStore(
|
||||
this.rootStore,
|
||||
`${this.baseUrl}/publications`,
|
||||
@@ -1003,9 +992,6 @@ export default class MetaStore implements IMetaStore {
|
||||
this.functions.setUrl(`${this.baseUrl}/functions`)
|
||||
this.functions.setHeaders(this.headers)
|
||||
|
||||
this.extensions.setUrl(`${this.baseUrl}/extensions`)
|
||||
this.extensions.setHeaders(this.headers)
|
||||
|
||||
this.publications.setUrl(`${this.baseUrl}/publications`)
|
||||
this.publications.setHeaders(this.headers)
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user