diff --git a/apps/studio/components/interfaces/Docs/Introduction.tsx b/apps/studio/components/interfaces/Docs/Introduction.tsx index 579e13dec51..6c4c68c167e 100644 --- a/apps/studio/components/interfaces/Docs/Introduction.tsx +++ b/apps/studio/components/interfaces/Docs/Introduction.tsx @@ -1,6 +1,10 @@ -import type { AutoApiService } from 'data/config/project-api-query' +import { useParams } from 'common' import Snippets from 'components/interfaces/Docs/Snippets' +import type { AutoApiService } from 'data/config/project-api-query' +import { useProjectPostgrestConfigQuery } from 'data/config/project-postgrest-config-query' + import CodeSnippet from './CodeSnippet' +import PublicSchemaNotEnabledAlert from './PublicSchemaNotEnabledAlert' interface Props { autoApiService: AutoApiService @@ -8,16 +12,22 @@ interface Props { } export default function Introduction({ autoApiService, selectedLang }: Props) { + const { ref: projectRef } = useParams() + + const { data: config } = useProjectPostgrestConfigQuery({ projectRef }) + + const isPublicSchemaEnabled = config?.db_schema + .split(',') + .map((name) => name.trim()) + .includes('public') + return ( - <> -
-
- -
-
- +
+
+ + + {!isPublicSchemaEnabled && } +
+
) } diff --git a/apps/studio/components/interfaces/Docs/Pages/Tables/Introduction.tsx b/apps/studio/components/interfaces/Docs/Pages/Tables/Introduction.tsx index 499b9709810..d3116933cb6 100644 --- a/apps/studio/components/interfaces/Docs/Pages/Tables/Introduction.tsx +++ b/apps/studio/components/interfaces/Docs/Pages/Tables/Introduction.tsx @@ -3,13 +3,22 @@ import Link from 'next/link' import CodeSnippet from 'components/interfaces/Docs/CodeSnippet' import GeneratingTypes from 'components/interfaces/Docs/GeneratingTypes' +import { useProjectPostgrestConfigQuery } from 'data/config/project-postgrest-config-query' +import PublicSchemaNotEnabledAlert from '../../PublicSchemaNotEnabledAlert' interface IntroductionProps { selectedLang: 'bash' | 'js' } const Introduction = ({ selectedLang }: IntroductionProps) => { - const { ref } = useParams() + const { ref: projectRef } = useParams() + + const { data: config } = useProjectPostgrestConfigQuery({ projectRef }) + + const isPublicSchemaEnabled = config?.db_schema + .split(',') + .map((name) => name.trim()) + .includes('public') return ( <> @@ -20,6 +29,8 @@ const Introduction = ({ selectedLang }: IntroductionProps) => { All views and tables in the public schema and accessible by the active database role for a request are available for querying.

+ + {!isPublicSchemaEnabled && } @@ -56,7 +67,7 @@ const Introduction = ({ selectedLang }: IntroductionProps) => { If you still want to use GraphQL, you can. Supabase provides you with a full Postgres database, so as long as your middleware can connect to the database then you can still use the tools you love. You can find the database connection details{' '} - in the settings. + in the settings.

diff --git a/apps/studio/components/interfaces/Docs/PublicSchemaNotEnabledAlert.tsx b/apps/studio/components/interfaces/Docs/PublicSchemaNotEnabledAlert.tsx new file mode 100644 index 00000000000..99be76b020f --- /dev/null +++ b/apps/studio/components/interfaces/Docs/PublicSchemaNotEnabledAlert.tsx @@ -0,0 +1,37 @@ +import { AlertDescription_Shadcn_, AlertTitle_Shadcn_, Alert_Shadcn_, Button } from 'ui' +import { Info } from 'lucide-react' +import ReactMarkdown from 'react-markdown' +import Link from 'next/link' +import { useParams } from 'common' + +const PublicSchemaNotEnabledAlert = () => { + const { ref: projectRef } = useParams() + + return ( + + + + The `public` schema for this project is not exposed + + + + You will not be able to query tables and views in the `public` schema via supabase-js or + HTTP clients. + + +
+ +
+
+
+ ) +} + +export default PublicSchemaNotEnabledAlert diff --git a/apps/studio/components/interfaces/Settings/API/PostgrestConfig.tsx b/apps/studio/components/interfaces/Settings/API/PostgrestConfig.tsx index da72304b181..c3d13ae124f 100644 --- a/apps/studio/components/interfaces/Settings/API/PostgrestConfig.tsx +++ b/apps/studio/components/interfaces/Settings/API/PostgrestConfig.tsx @@ -16,29 +16,50 @@ import { useProjectPostgrestConfigQuery } from 'data/config/project-postgrest-co import { useProjectPostgrestConfigUpdateMutation } from 'data/config/project-postgrest-config-update-mutation' import { useSchemasQuery } from 'data/database/schemas-query' import { useCheckPermissions } from 'hooks' -import { Form, IconAlertCircle, Input, InputNumber } from 'ui' -import MultiSelect from 'ui-patterns/MultiSelect' +import { AlertCircle, Info } from 'lucide-react' +import { + AlertDescription_Shadcn_, + AlertTitle_Shadcn_, + Alert_Shadcn_, + Button, + Form, + Input, + InputNumber, +} from 'ui' +import { MultiSelectV2 } from 'ui-patterns/MultiSelect/MultiSelectV2' +import ShimmeringLoader from 'ui-patterns/ShimmeringLoader' + +import { useDatabaseExtensionsQuery } from 'data/database-extensions/database-extensions-query' +import Link from 'next/link' const PostgrestConfig = () => { const { ref: projectRef } = useParams() const { project } = useProjectContext() - const { data: schemas } = useSchemasQuery({ + + const { data: schemas, isLoading: isLoadingSchemas } = useSchemasQuery({ projectRef: project?.ref, connectionString: project?.connectionString, }) const { data: config, isError } = useProjectPostgrestConfigQuery({ projectRef }) + const { mutate: updatePostgrestConfig, isLoading: isUpdating } = useProjectPostgrestConfigUpdateMutation({ onSuccess: () => { toast.success('Successfully saved settings') }, }) + const canUpdatePostgrestConfig = useCheckPermissions( PermissionAction.UPDATE, 'custom_config_postgrest' ) + const { data: extensions } = useDatabaseExtensionsQuery({ + projectRef: project?.ref, + connectionString: project?.connectionString, + }) + const formId = 'project-postgres-config' const initialValues = { db_schema: '', max_rows: '', db_extra_search_path: '', db_pool: '' } @@ -53,7 +74,6 @@ const PostgrestConfig = () => { }) } - const permanentSchema = ['public', 'storage'] const hiddenSchema = ['auth', 'pgbouncer', 'hooks', 'extensions'] const schema = schemas @@ -66,15 +86,22 @@ const PostgrestConfig = () => { id: x.id, value: x.name, name: x.name, - disabled: indexOf(permanentSchema, x.name) >= 0 ? true : false, + disabled: false, } }) ?? [] + const isPublicSchemaEnabled = config?.db_schema + .split(',') + .map((name) => name.trim()) + .includes('public') + + const isGraphqlExtensionEnabled = + (extensions ?? []).find((ext) => ext.name === 'pg_graphql')?.installed_version !== null + return (
{}} onSubmit={updateConfig}> {({ handleReset, resetForm, values, initialValues }: any) => { const hasChanges = JSON.stringify(values) !== JSON.stringify(initialValues) - // [Alaister] although this "technically" is breaking the rules of React hooks // it won't error because the hooks are always rendered in the same order // eslint-disable-next-line react-hooks/rules-of-hooks @@ -86,6 +113,7 @@ const PostgrestConfig = () => { db_extra_search_path: config.db_extra_search_path ?? '', db_pool: config.db_pool || null, } + resetForm({ values, initialValues: values }) } }, [config]) @@ -114,51 +142,81 @@ const PostgrestConfig = () => { > {isError ? (
- +

Failed to retrieve API settings

) : ( <> Exposed schemas}> - - {schema.length >= 1 && ( - + {isLoadingSchemas ? ( +
+ + +
+ ) : ( + + {schema.length >= 1 && ( +
+ { + let updatedValues: any = values + updatedValues.db_schema = event.join(', ') + resetForm({ values: updatedValues, initialValues: updatedValues }) + updateConfig({ ...updatedValues }) + }} + /> +

The schemas to expose in your API. Tables, views and stored procedures in these schemas will get API endpoints. - public and{' '} - storage are protected by default. - - } - emptyMessage={ - <> - -

-

- No schema available to choose -

-

- New schemas you create will appear here -

-
- - } - // value must be passed as array of strings - value={(values?.db_schema ?? '').replace(/ /g, '').split(',')} - // onChange returns array of strings - onChange={(event) => { - let updatedValues: any = values - updatedValues.db_schema = event.join(', ') - resetForm({ values: updatedValues, initialValues: updatedValues }) - updateConfig({ ...updatedValues }) - }} - /> - )} - +

+ + {!isPublicSchemaEnabled && ( + + + + The public schema for this project is not exposed + + +

+ You will not be able to query tables and views in the{' '} + public schema via supabase-js or HTTP clients. +

+ {isGraphqlExtensionEnabled && ( +
+
+ Tables in the public schema are still exposed + over our GraphQL endpoints. +
+

+ +

+
+ )} +
+
+ )} +
+ )} +
+ )}
+ Extra search path}> { -
+