Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
PolicyTableRow,
PolicyTableRowProps,
} from 'components/interfaces/Auth/Policies/PolicyTableRow'
import ProtectedSchemaWarning from 'components/interfaces/Database/ProtectedSchemaWarning'
import { ProtectedSchemaWarning } from 'components/interfaces/Database/ProtectedSchemaWarning'
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
import NoSearchResults from 'components/to-be-cleaned/NoSearchResults'
import ProductEmptyState from 'components/to-be-cleaned/ProductEmptyState'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
useEnumeratedTypesQuery,
} from 'data/enumerated-types/enumerated-types-query'
import { useQuerySchemaState } from 'hooks/misc/useSchemaQueryState'
import { PROTECTED_SCHEMAS } from 'lib/constants/schemas'
import { useIsProtectedSchema } from 'hooks/useProtectedSchemas'
import {
Button,
DropdownMenu,
Expand All @@ -22,7 +22,7 @@ import {
DropdownMenuTrigger,
Input,
} from 'ui'
import ProtectedSchemaWarning from '../ProtectedSchemaWarning'
import { ProtectedSchemaWarning } from '../ProtectedSchemaWarning'
import CreateEnumeratedTypeSidePanel from './CreateEnumeratedTypeSidePanel'
import DeleteEnumeratedTypeModal from './DeleteEnumeratedTypeModal'
import EditEnumeratedTypeSidePanel from './EditEnumeratedTypeSidePanel'
Expand Down Expand Up @@ -52,11 +52,7 @@ const EnumeratedTypes = () => {
)
: enumeratedTypes.filter((x) => x.schema === selectedSchema)

const protectedSchemas = (schemas ?? []).filter((schema) =>
PROTECTED_SCHEMAS.includes(schema?.name ?? '')
)
const schema = schemas?.find((schema) => schema.name === selectedSchema)
const isLocked = protectedSchemas.some((s) => s.id === schema?.id)
const { isSchemaLocked } = useIsProtectedSchema({ schema: selectedSchema })

return (
<div className="space-y-4">
Expand All @@ -81,7 +77,7 @@ const EnumeratedTypes = () => {

<div className="flex items-center gap-2">
<DocsButton href="https://www.postgresql.org/docs/current/datatype-enum.html" />
{!isLocked && (
{!isSchemaLocked && (
<Button
className="ml-auto flex-1"
type="primary"
Expand All @@ -93,7 +89,9 @@ const EnumeratedTypes = () => {
</div>
</div>

{isLocked && <ProtectedSchemaWarning schema={selectedSchema} entity="enumerated types" />}
{isSchemaLocked && (
<ProtectedSchemaWarning schema={selectedSchema} entity="enumerated types" />
)}

{isLoading && <GenericSkeletonLoader />}

Expand Down Expand Up @@ -140,7 +138,7 @@ const EnumeratedTypes = () => {
<Table.td>{type.name}</Table.td>
<Table.td>{type.enums.join(', ')}</Table.td>
<Table.td>
{!isLocked && (
{!isSchemaLocked && (
<div className="flex justify-end items-center space-x-2">
<DropdownMenu>
<DropdownMenuTrigger asChild>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { useDatabaseExtensionsQuery } from 'data/database-extensions/database-ex
import { useDatabaseFunctionCreateMutation } from 'data/database-functions/database-functions-create-mutation'
import { DatabaseFunction } from 'data/database-functions/database-functions-query'
import { useDatabaseFunctionUpdateMutation } from 'data/database-functions/database-functions-update-mutation'
import { PROTECTED_SCHEMAS } from 'lib/constants/schemas'
import { useProtectedSchemas } from 'hooks/useProtectedSchemas'
import type { FormSchema } from 'types'
import {
Button,
Expand Down Expand Up @@ -149,6 +149,8 @@ const CreateFunction = ({ func, visible, setVisible }: CreateFunctionProps) => {
}
}, [visible, func])

const { data: protectedSchemas } = useProtectedSchemas()

return (
<Sheet open={visible} onOpenChange={() => isClosingSidePanel()}>
<SheetContent
Expand Down Expand Up @@ -205,7 +207,7 @@ const CreateFunction = ({ func, visible, setVisible }: CreateFunctionProps) => {
<SchemaSelector
portal={false}
selectedSchemaName={field.value}
excludedSchemas={PROTECTED_SCHEMAS}
excludedSchemas={protectedSchemas?.map((s) => s.name)}
size="small"
onSelectSchema={(name) => field.onChange(name)}
/>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { PostgresFunction } from '@supabase/postgres-meta'
import { PermissionAction } from '@supabase/shared-types/out/constants'
import { noop, partition } from 'lodash'
import { noop } from 'lodash'
import { Search } from 'lucide-react'
import { useRouter } from 'next/router'

Expand All @@ -16,10 +16,10 @@ import { useDatabaseFunctionsQuery } from 'data/database-functions/database-func
import { useSchemasQuery } from 'data/database/schemas-query'
import { useCheckPermissions } from 'hooks/misc/useCheckPermissions'
import { useQuerySchemaState } from 'hooks/misc/useSchemaQueryState'
import { PROTECTED_SCHEMAS } from 'lib/constants/schemas'
import { useIsProtectedSchema } from 'hooks/useProtectedSchemas'
import { useAiAssistantStateSnapshot } from 'state/ai-assistant-state'
import { AiIconAnimation, Input } from 'ui'
import ProtectedSchemaWarning from '../../ProtectedSchemaWarning'
import { ProtectedSchemaWarning } from '../../ProtectedSchemaWarning'
import FunctionList from './FunctionList'

interface FunctionsListProps {
Expand Down Expand Up @@ -60,11 +60,8 @@ const FunctionsList = ({
projectRef: project?.ref,
connectionString: project?.connectionString,
})
const [protectedSchemas] = partition(schemas ?? [], (schema) =>
PROTECTED_SCHEMAS.includes(schema?.name ?? '')
)
const foundSchema = schemas?.find((schema) => schema.name === selectedSchema)
const isLocked = protectedSchemas.some((s) => s.id === foundSchema?.id)

const { isSchemaLocked } = useIsProtectedSchema({ schema: selectedSchema })

const {
data: functions,
Expand Down Expand Up @@ -126,7 +123,7 @@ const FunctionsList = ({
</div>

<div className="flex items-center gap-x-2">
{!isLocked && (
{!isSchemaLocked && (
<>
<ButtonTooltip
disabled={!canCreateFunctions}
Expand Down Expand Up @@ -169,7 +166,7 @@ const FunctionsList = ({
</div>
</div>

{isLocked && <ProtectedSchemaWarning schema={selectedSchema} entity="functions" />}
{isSchemaLocked && <ProtectedSchemaWarning schema={selectedSchema} entity="functions" />}

<Table
className="table-fixed overflow-x-auto"
Expand All @@ -192,7 +189,7 @@ const FunctionsList = ({
<FunctionList
schema={selectedSchema}
filterString={filterString}
isLocked={isLocked}
isLocked={isSchemaLocked}
editFunction={editFunction}
deleteFunction={deleteFunction}
/>
Expand Down
18 changes: 7 additions & 11 deletions apps/studio/components/interfaces/Database/Indexes/Indexes.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { partition, sortBy } from 'lodash'
import { sortBy } from 'lodash'
import { AlertCircle, Search, Trash } from 'lucide-react'
import { useEffect, useState } from 'react'
import { toast } from 'sonner'
Expand All @@ -14,10 +14,10 @@ import { useDatabaseIndexDeleteMutation } from 'data/database-indexes/index-dele
import { DatabaseIndex, useIndexesQuery } from 'data/database-indexes/indexes-query'
import { useSchemasQuery } from 'data/database/schemas-query'
import { useQuerySchemaState } from 'hooks/misc/useSchemaQueryState'
import { PROTECTED_SCHEMAS } from 'lib/constants/schemas'
import { useIsProtectedSchema } from 'hooks/useProtectedSchemas'
import { Button, Input, SidePanel } from 'ui'
import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal'
import ProtectedSchemaWarning from '../ProtectedSchemaWarning'
import { ProtectedSchemaWarning } from '../ProtectedSchemaWarning'
import CreateIndexSidePanel from './CreateIndexSidePanel'

const Indexes = () => {
Expand Down Expand Up @@ -58,11 +58,7 @@ const Indexes = () => {
},
})

const [protectedSchemas] = partition(schemas ?? [], (schema) =>
PROTECTED_SCHEMAS.includes(schema?.name ?? '')
)
const schema = schemas?.find((schema) => schema.name === selectedSchema)
const isLocked = protectedSchemas.some((s) => s.id === schema?.id)
const { isSchemaLocked } = useIsProtectedSchema({ schema: selectedSchema })

const sortedIndexes = sortBy(allIndexes ?? [], (index) => index.name.toLocaleLowerCase())
const indexes =
Expand Down Expand Up @@ -122,7 +118,7 @@ const Indexes = () => {
icon={<Search size={14} />}
/>

{!isLocked && (
{!isSchemaLocked && (
<Button
className="ml-auto flex-grow lg:flex-grow-0"
type="primary"
Expand All @@ -134,7 +130,7 @@ const Indexes = () => {
)}
</div>

{isLocked && <ProtectedSchemaWarning schema={selectedSchema} entity="indexes" />}
{isSchemaLocked && <ProtectedSchemaWarning schema={selectedSchema} entity="indexes" />}

{isLoadingIndexes && <GenericSkeletonLoader />}

Expand Down Expand Up @@ -190,7 +186,7 @@ const Indexes = () => {
<Button type="default" onClick={() => setSelectedIndex(index)}>
View definition
</Button>
{!isLocked && (
{!isSchemaLocked && (
<Button
type="text"
className="px-1"
Expand Down
117 changes: 75 additions & 42 deletions apps/studio/components/interfaces/Database/ProtectedSchemaWarning.tsx
Original file line number Diff line number Diff line change
@@ -1,37 +1,35 @@
import { useState } from 'react'
import { AlertDescription_Shadcn_, AlertTitle_Shadcn_, Alert_Shadcn_, Button, Modal } from 'ui'

import { PROTECTED_SCHEMAS } from 'lib/constants/schemas'
import { AlertCircle } from 'lucide-react'
import {
Button,
Dialog,
DialogContent,
DialogFooter,
DialogHeader,
DialogSection,
DialogSectionSeparator,
DialogTitle,
DialogTrigger,
cn,
} from 'ui'

export const ProtectedSchemaModal = ({
visible,
onClose,
}: {
visible: boolean
onClose: () => void
}) => {
import { INTERNAL_SCHEMAS, useIsProtectedSchema } from 'hooks/useProtectedSchemas'
import { Admonition } from 'ui-patterns'

export const ProtectedSchemaDialog = ({ onClose }: { onClose: () => void }) => {
return (
<Modal
size="medium"
visible={visible}
header="Schemas managed by Supabase"
customFooter={
<div className="flex items-center justify-end space-x-2">
<Button type="default" onClick={() => onClose()}>
Understood
</Button>
</div>
}
onCancel={() => onClose()}
>
<Modal.Content className="space-y-2">
<>
<DialogHeader>
<DialogTitle>Schemas managed by Supabase</DialogTitle>
</DialogHeader>
<DialogSectionSeparator />
<DialogSection className="space-y-2 prose">
<p className="text-sm">
The following schemas are managed by Supabase and are currently protected from write
access through the dashboard.
</p>
<div className="flex flex-wrap gap-1">
{PROTECTED_SCHEMAS.map((schema) => (
{INTERNAL_SCHEMAS.map((schema) => (
<code key={schema} className="text-xs">
{schema}
</code>
Expand All @@ -45,32 +43,67 @@ export const ProtectedSchemaModal = ({
You can, however, still interact with those schemas through the SQL Editor although we
advise you only do so if you know what you are doing.
</p>
</Modal.Content>
</Modal>
</DialogSection>
<DialogFooter>
<div className="flex items-center justify-end space-x-2">
<Button type="default" onClick={onClose}>
Understood
</Button>
</div>
</DialogFooter>
</>
)
}

const ProtectedSchemaWarning = ({ schema, entity }: { schema: string; entity: string }) => {
export const ProtectedSchemaWarning = ({
size = 'md',
schema,
entity,
}: {
size?: 'sm' | 'md'
schema: string
entity: string
}) => {
const [showModal, setShowModal] = useState(false)
const { isSchemaLocked, reason } = useIsProtectedSchema({ schema })

if (!isSchemaLocked) return null

return (
<>
<Alert_Shadcn_>
<AlertCircle strokeWidth={2} />
<AlertTitle_Shadcn_>Currently viewing {entity} from a protected schema</AlertTitle_Shadcn_>
<AlertDescription_Shadcn_>
<Admonition
showIcon={false}
type="note"
title={
size === 'sm' ? `Viewing protected schema` : `Viewing ${entity} from a protected schema`
}
className={cn(
'[&>div>p]:prose [&>div>p]:max-w-full [&>div>p]:!leading-normal',
size === 'sm' ? '[&>div>p]:text-xs' : '[&>div>p]:text-sm'
)}
>
{reason === 'fdw' ? (
<p>
The <code className="text-xs">{schema}</code> schema is used by Supabase to connect to
analytics buckets and is read-only through the dashboard.
</p>
) : (
<>
<p className="mb-2">
The <code className="text-xs">{schema}</code> schema is managed by Supabase and is
read-only through the dashboard.
</p>
<Button type="default" size="tiny" onClick={() => setShowModal(true)}>
Learn more
</Button>
</AlertDescription_Shadcn_>
</Alert_Shadcn_>
<ProtectedSchemaModal visible={showModal} onClose={() => setShowModal(false)} />
</>
<Dialog open={showModal} onOpenChange={setShowModal}>
<DialogTrigger asChild>
<Button type="default" size="tiny" onClick={() => setShowModal(true)}>
Learn more
</Button>
</DialogTrigger>
<DialogContent>
<ProtectedSchemaDialog onClose={() => setShowModal(false)} />
</DialogContent>
</Dialog>
</>
)}
</Admonition>
)
}

export default ProtectedSchemaWarning
Loading
Loading