mirror of
https://github.com/supabase/supabase.git
synced 2026-07-03 21:54:19 +08:00
219 lines
6.5 KiB
TypeScript
219 lines
6.5 KiB
TypeScript
import { FC, useState, useEffect } from 'react'
|
|
import { observer } from 'mobx-react-lite'
|
|
import { Typography } from '@supabase/ui'
|
|
import { useStore } from 'hooks'
|
|
import { pluckObjectFields } from 'lib/helpers'
|
|
import Loading from 'components/ui/Loading'
|
|
import Panel from 'components/ui/Panel'
|
|
import Divider from 'components/ui/Divider'
|
|
import { AutoField } from 'uniforms-bootstrap4'
|
|
import { API_URL } from 'lib/constants'
|
|
import { patch } from 'lib/common/fetch'
|
|
import ToggleField from 'components/to-be-cleaned/forms/ToggleField'
|
|
import SchemaFormPanel from 'components/to-be-cleaned/forms/SchemaFormPanel'
|
|
import { Input } from '@supabase/ui'
|
|
|
|
interface Props {}
|
|
|
|
const ConnectionPooling: FC<Props> = () => {
|
|
const { ui, app } = useStore()
|
|
const projectRef = ui.selectedProject?.ref ?? 'default'
|
|
|
|
const [isLoading, setIsLoading] = useState<boolean>(true)
|
|
const [poolingConfiguration, setPoolingConfiguration] = useState<any>()
|
|
|
|
useEffect(() => {
|
|
fetchPoolingConfiguration()
|
|
}, [])
|
|
|
|
const fetchPoolingConfiguration = async () => {
|
|
setIsLoading(true)
|
|
const response = await app.database.getPoolingConfiguration(projectRef)
|
|
setPoolingConfiguration(response)
|
|
setIsLoading(false)
|
|
}
|
|
|
|
if (isLoading) return <Loading />
|
|
if (poolingConfiguration.error) {
|
|
return (
|
|
<div className="p-4">
|
|
<Typography.Text type="secondary">Error loading pooling configuration</Typography.Text>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
const { project } = poolingConfiguration
|
|
|
|
// for older projects
|
|
if (!project.pgbouncer_enabled && project.pool_mode == null)
|
|
return (
|
|
<Panel
|
|
title={
|
|
<Typography.Title key="panel-title" level={5} className="mb-0">
|
|
Connection Pooling is not available for this project
|
|
</Typography.Title>
|
|
}
|
|
>
|
|
<Panel.Content>
|
|
<Typography.Text type="secondary">Please start a new project to enable this feature.</Typography.Text>
|
|
</Panel.Content>
|
|
</Panel>
|
|
)
|
|
const formModel = project
|
|
const DB_FIELDS = ['db_host', 'db_name', 'db_port', 'db_user', 'inserted_at']
|
|
const connectionInfo = pluckObjectFields(formModel, DB_FIELDS)
|
|
const BOUNCER_FIELDS = [
|
|
'default_pool_size',
|
|
'ignore_startup_parameters',
|
|
'pool_mode',
|
|
'pgbouncer_enabled',
|
|
]
|
|
const bouncerInfo = pluckObjectFields(formModel, BOUNCER_FIELDS)
|
|
|
|
return (
|
|
<PgbouncerConfig projectRef={projectRef} bouncerInfo={bouncerInfo} connectionInfo={connectionInfo} />
|
|
)
|
|
}
|
|
|
|
export default observer(ConnectionPooling)
|
|
|
|
interface ConfigProps {
|
|
projectRef: string
|
|
bouncerInfo: {default_pool_size: number, ignore_startup_parameters: 'string', pool_mode: string, pgbouncer_enabled: boolean},
|
|
connectionInfo: {db_host: string, db_name: string, db_port: number, db_user: string, inserted_at: string}
|
|
}
|
|
|
|
export const PgbouncerConfig: FC<ConfigProps> = observer(({ projectRef, bouncerInfo, connectionInfo }) => {
|
|
|
|
const { ui } = useStore()
|
|
|
|
const [updates, setUpdates] = useState<any>({
|
|
pgbouncer_enabled: bouncerInfo.pgbouncer_enabled,
|
|
pool_mode: bouncerInfo.pool_mode || 'transaction',
|
|
default_pool_size: bouncerInfo.default_pool_size || '',
|
|
ignore_startup_parameters: bouncerInfo.ignore_startup_parameters || '',
|
|
})
|
|
|
|
const updateConfig = async (updatedConfig: any) => {
|
|
try {
|
|
const response = await patch(`${API_URL}/props/pooling/${projectRef}/config`, updatedConfig)
|
|
if (response.error) {
|
|
throw response.error
|
|
} else {
|
|
setUpdates({ ...response.project })
|
|
ui.setNotification({ category: 'success', message: 'Successfully saved settings' })
|
|
}
|
|
} catch (error: any) {
|
|
ui.setNotification({
|
|
category: 'error',
|
|
message: `Failed to update config: ${error.message}`,
|
|
})
|
|
}
|
|
}
|
|
|
|
const formSchema = {
|
|
properties: {
|
|
pgbouncer_enabled: {
|
|
title: 'Enabled',
|
|
type: 'boolean',
|
|
help: 'Activates / deactivates Connection Pooling.',
|
|
},
|
|
pool_mode: {
|
|
title: 'Pool Mode',
|
|
type: 'string',
|
|
options: [
|
|
{
|
|
label: 'Transaction',
|
|
value: 'transaction',
|
|
},
|
|
{
|
|
label: 'Session',
|
|
value: 'session',
|
|
},
|
|
{
|
|
label: 'Statement',
|
|
value: 'statement',
|
|
},
|
|
],
|
|
},
|
|
ignore_startup_parameters: {
|
|
title: 'Ignore Startup Parameters',
|
|
type: 'string',
|
|
readOnly: true,
|
|
help: 'Defaults are either blank or "extra_float_digits"',
|
|
},
|
|
},
|
|
required: ['pool_mode'],
|
|
type: 'object',
|
|
}
|
|
|
|
return (
|
|
<SchemaFormPanel
|
|
title="Connection Pooling"
|
|
schema={formSchema}
|
|
model={updates}
|
|
submitLabel="Save"
|
|
cancelLabel="Cancel"
|
|
onChangeModel={(model: any) => setUpdates(model)}
|
|
onSubmit={(model: any) => updateConfig(model)}
|
|
onReset={() => setUpdates(bouncerInfo)}
|
|
>
|
|
<div className="space-y-6 py-4">
|
|
<ToggleField name="pgbouncer_enabled" />
|
|
|
|
<Divider light />
|
|
|
|
{updates.pgbouncer_enabled && (
|
|
<>
|
|
<AutoField
|
|
name="pool_mode"
|
|
showInlineError
|
|
errorMessage="You must select one of the three options"
|
|
/>
|
|
<div className="flex !mt-1" style={{ marginLeft: 'calc(33% + 0.5rem)' }}>
|
|
<p className="text-sm text-scale-900">
|
|
Specify when a connection can be returned to the pool. To find out the most
|
|
suitable mode for your use case,{' '}
|
|
<a
|
|
className="text-green-900"
|
|
target="_blank"
|
|
href="https://supabase.com/docs/guides/database/connecting-to-postgres#connection-pool"
|
|
>
|
|
click here
|
|
</a>
|
|
.
|
|
</p>
|
|
</div>
|
|
<Divider light />
|
|
<AutoField name="ignore_startup_parameters" />
|
|
</>
|
|
)}
|
|
<Divider light />
|
|
<Input
|
|
className="input-mono"
|
|
layout="horizontal"
|
|
readOnly
|
|
copy
|
|
disabled
|
|
value={connectionInfo.db_port}
|
|
label="Port"
|
|
/>
|
|
<Divider light />
|
|
<Input
|
|
className="input-mono"
|
|
layout="vertical"
|
|
readOnly
|
|
copy
|
|
disabled
|
|
label="Connection string"
|
|
value={
|
|
`postgres://${connectionInfo.db_user}:[YOUR-PASSWORD]@` +
|
|
`${connectionInfo.db_host}:${connectionInfo.db_port}` +
|
|
`/${connectionInfo.db_name}`
|
|
}
|
|
/>
|
|
</div>
|
|
</SchemaFormPanel>
|
|
)
|
|
})
|