chore: Disable some of the Studio features on Multigres projects (#46775)

This PR disables the following features on Multigres projects

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
  * Enhanced replication interface with improved visual states.

* **Bug Fixes**
* Added validation to prevent incompatible database configuration
combinations.

* **Changes**
* High Availability projects now display informational notices
indicating unavailable features: Realtime, Replication, and PITR
backups.

* **Removed**
  * Removed redundant UI component from the application.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Gildas Garcia <1122076+djhi@users.noreply.github.com>
This commit is contained in:
Ivan VasilovandGildas Garcia authored and GitHub committed 2026-06-15 14:09:41 +02:00
1 parent dfc2dede05
commit e1ccc31fcc
7 files changed
+188 -68

No files matched your search

@@ -0,0 +1,57 @@
import { Background, ColorMode, ReactFlow, ReactFlowProvider } from '@xyflow/react'
import { useTheme } from 'next-themes'
import { PrimaryDatabaseNode, ReadReplicaNode, ReplicationNode } from './Nodes'
import '@xyflow/react/dist/style.css'
import { SmoothstepEdge } from './Edges'
export const EmptyReplicationDiagram = () => {
return (
<ReactFlowProvider>
<ReplicationDiagramContent />
</ReactFlowProvider>
)
}
const nodeTypes = {
primary: PrimaryDatabaseNode,
replication: ReplicationNode,
readReplica: ReadReplicaNode,
}
const edgeTypes = { smoothstep: SmoothstepEdge }
const ReplicationDiagramContent = () => {
const { resolvedTheme } = useTheme()
const backgroundPatternColor =
resolvedTheme === 'dark' ? 'rgba(255, 255, 255, 0.3)' : 'rgba(0, 0, 0, 0.4)'
return (
<div className="nowheel relative min-h-[350px]">
<ReactFlow
// FIXME: https://github.com/xyflow/xyflow/issues/4876
colorMode={'' as unknown as ColorMode}
fitView
fitViewOptions={{ minZoom: 0.8, maxZoom: 0.9 }}
className="bg"
zoomOnPinch={false}
zoomOnScroll={false}
nodesDraggable={false}
nodesConnectable={false}
zoomOnDoubleClick={false}
edgesFocusable={false}
edgesReconnectable={false}
defaultNodes={[]}
defaultEdges={[]}
nodeTypes={nodeTypes}
edgeTypes={edgeTypes}
proOptions={{ hideAttribution: true }}
>
<Background color={backgroundPatternColor} />
</ReactFlow>
</div>
)
}
@@ -44,7 +44,10 @@ export const FormSchema = z
useOrioleDb: z.boolean(),
})
.superRefine(
({ dbPassStrength, dbPassStrengthWarning, highAvailability, cloudProvider }, ctx) => {
(
{ dbPassStrength, dbPassStrengthWarning, highAvailability, cloudProvider, useOrioleDb },
ctx
) => {
if (dbPassStrength < DEFAULT_MINIMUM_PASSWORD_STRENGTH) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
@@ -59,6 +62,19 @@ export const FormSchema = z
message: 'High availability is only supported on AWS (Revamped)',
})
}
if (highAvailability && useOrioleDb) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
path: ['highAvailability'],
message: 'High availability is not supported with OrioleDB images',
})
ctx.addIssue({
code: z.ZodIssueCode.custom,
path: ['useOrioleDb'],
message: 'High availability is not supported with OrioleDB images',
})
}
}
)
@@ -1,5 +1,9 @@
import { Realtime } from 'icons'
import { ExternalLink } from 'lucide-react'
import Head from 'next/head'
import { useRouter } from 'next/router'
import type { PropsWithChildren } from 'react'
import { Button } from 'ui'
import { ProjectLayout } from '../ProjectLayout'
import { generateRealtimeMenu } from './RealtimeMenu.utils'
@@ -31,6 +35,42 @@ export const RealtimeLayout = ({ title, children }: PropsWithChildren<RealtimeLa
const page = router.pathname.split('/')[4]
const menu = generateRealtimeMenu(project)
if (!!project?.high_availability) {
return (
<>
<Head>
<title>{title}</title>
<meta name="description" content="Supabase Studio" />
</Head>
<main
id="panel-project-content"
className="h-full w-full xl:min-w-[600px] flex items-center justify-center overflow-y-auto overflow-x-hidden bg-dash-sidebar p-6 @container"
>
<div className="flex max-w-md flex-col items-center gap-y-5 text-center">
<div className="flex h-12 w-12 items-center justify-center rounded-lg border border-strong bg-surface-100 text-foreground-light">
<Realtime size={22} strokeWidth={1.5} />
</div>
<div className="flex flex-col gap-y-2">
<h3 className="text-base text-foreground">
Realtime is not available for High Availability projects
</h3>
<p className="text-sm text-foreground-light">
Realtime is not currently available for projects with High Availability. Reach out
to our support team if you're interested in using this feature with your High
Availability project.
</p>
</div>
<Button asChild type="default" icon={<ExternalLink />}>
<a href="https://supabase.com/support" target="_blank" rel="noopener noreferrer">
Contact support
</a>
</Button>
</div>
</main>
</>
)
}
return (
<ProjectLayout
product="Realtime"
@@ -1,40 +0,0 @@
import { BookOpenText } from 'lucide-react'
import { ButtonTooltip } from './ButtonTooltip'
import { useTrack } from '@/lib/telemetry/track'
import { useAppStateSnapshot } from '@/state/app-state'
interface APIDocsButtonProps {
section?: string[]
source: string
label?: string
tooltip?: string
}
export const APIDocsButton = ({ section, source, label, tooltip }: APIDocsButtonProps) => {
const snap = useAppStateSnapshot()
const track = useTrack()
return (
<ButtonTooltip
size="tiny"
type="default"
onClick={() => {
if (section) snap.setActiveDocsSection(section)
snap.setShowProjectApiDocs(true)
track('api_docs_opened', { source })
}}
icon={<BookOpenText />}
className={label ? undefined : 'w-7'}
tooltip={{
content: {
side: 'bottom',
text: tooltip ?? 'API Docs',
},
}}
>
{label}
</ButtonTooltip>
)
}
@@ -101,6 +101,18 @@ const PITR = () => {
)
}
if (project?.high_availability) {
return (
<Admonition
type="default"
title="Database backups are not available for High Availability projects"
description="High Availability projects do not support Point-in-Time Recovery (PITR) backups"
>
<DocsButton abbrev={false} className="mt-2" href={DOCS_URL} />
</Admonition>
)
}
return (
<>
{isLoading && <GenericSkeletonLoader />}
@@ -1,21 +1,24 @@
import { useParams } from 'common'
import { Admonition } from 'ui-patterns/admonition'
import { GenericSkeletonLoader } from 'ui-patterns/ShimmeringLoader'
import { Destinations } from '@/components/interfaces/Database/Replication/Destinations'
import { ReplicationDiagram } from '@/components/interfaces/Database/Replication/ReplicationDiagram'
import { EmptyReplicationDiagram } from '@/components/interfaces/Database/Replication/ReplicationDiagram/EmptyReplicationDiagram'
import DatabaseLayout from '@/components/layouts/DatabaseLayout/DatabaseLayout'
import { DefaultLayout } from '@/components/layouts/DefaultLayout'
import { ScaffoldContainer, ScaffoldSection } from '@/components/layouts/Scaffold'
import { UnknownInterface } from '@/components/ui/UnknownInterface'
import { useIsFeatureEnabled } from '@/hooks/misc/useIsFeatureEnabled'
import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject'
import { PipelineRequestStatusProvider } from '@/state/replication-pipeline-request-status'
import type { NextPageWithLayout } from '@/types'
const DatabaseReplicationPage: NextPageWithLayout = () => {
const { ref } = useParams()
const { data: selectedProject, isPending } = useSelectedProjectQuery()
const showPgReplicate = useIsFeatureEnabled('database:replication')
if (!showPgReplicate) {
return <UnknownInterface urlBack={`/project/${ref}/database/schemas`} />
return <UnknownInterface urlBack={`/project/${selectedProject?.ref}/database/schemas`} />
}
return (
@@ -34,13 +37,45 @@ const DatabaseReplicationPage: NextPageWithLayout = () => {
</ScaffoldSection>
</ScaffoldContainer>
<ReplicationDiagram />
{isPending ? (
<ScaffoldContainer>
<GenericSkeletonLoader />
</ScaffoldContainer>
) : selectedProject?.high_availability ? (
<>
<EmptyReplicationDiagram />
<ScaffoldContainer>
<ScaffoldSection isFullWidth className="pt-6!">
<Destinations />
</ScaffoldSection>
</ScaffoldContainer>
<ScaffoldContainer>
<ScaffoldSection isFullWidth className="pt-6!">
<Admonition
variant="default"
title="Replication is not available for High Availability projects"
>
Replication is not currently available for projects with High Availability. Please
contact{' '}
<a
href="https://supabase.com/support"
target="_blank"
rel="noopener noreferrer"
className="text-primary underline"
>
support
</a>{' '}
if you are interested in using this feature with your High Availability project.
</Admonition>
</ScaffoldSection>
</ScaffoldContainer>
</>
) : (
<>
<ReplicationDiagram />
<ScaffoldContainer>
<ScaffoldSection isFullWidth className="pt-6!">
<Destinations />
</ScaffoldSection>
</ScaffoldContainer>
</>
)}
</PipelineRequestStatusProvider>
)
}
+18 -18
View File
@@ -16739,8 +16739,8 @@ packages:
resolution: {integrity: sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==}
engines: {node: '>=6'}
tslib@2.6.2:
resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==}
tslib@2.6.3:
resolution: {integrity: sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==}
tslib@2.8.1:
resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
@@ -19117,7 +19117,7 @@ snapshots:
'@dnd-kit/utilities': 3.2.2(react@19.2.6)
react: 19.2.6
react-dom: 19.2.6(react@19.2.6)
tslib: 2.6.2
tslib: 2.8.1
'@dnd-kit/modifiers@9.0.0(@dnd-kit/core@6.3.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(react@19.2.6)':
dependencies:
@@ -19131,12 +19131,12 @@ snapshots:
'@dnd-kit/core': 6.3.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6)
'@dnd-kit/utilities': 3.2.2(react@19.2.6)
react: 19.2.6
tslib: 2.6.2
tslib: 2.8.1
'@dnd-kit/utilities@3.2.2(react@19.2.6)':
dependencies:
react: 19.2.6
tslib: 2.6.2
tslib: 2.8.1
'@dotenvx/dotenvx@1.51.0':
dependencies:
@@ -19571,7 +19571,7 @@ snapshots:
dependencies:
'@graphql-codegen/plugin-helpers': 5.1.0(graphql@16.11.0)
graphql: 16.11.0
tslib: 2.6.2
tslib: 2.6.3
'@graphql-codegen/cli@5.0.5(@parcel/watcher@2.5.6)(@types/node@22.13.14)(encoding@0.1.13)(graphql-sock@1.0.1(graphql@16.11.0))(graphql@16.11.0)(supports-color@8.1.1)(typescript@6.0.2)':
dependencies:
@@ -19642,7 +19642,7 @@ snapshots:
'@graphql-typed-document-node/core': 3.2.0(graphql@16.11.0)
graphql: 16.11.0
graphql-sock: 1.0.1(graphql@16.11.0)
tslib: 2.6.2
tslib: 2.6.3
transitivePeerDependencies:
- encoding
@@ -19652,7 +19652,7 @@ snapshots:
'@graphql-tools/schema': 10.0.23(graphql@16.11.0)
'@graphql-tools/utils': 10.8.6(graphql@16.11.0)
graphql: 16.11.0
tslib: 2.6.2
tslib: 2.6.3
'@graphql-codegen/gql-tag-operations@4.0.17(encoding@0.1.13)(graphql@16.11.0)':
dependencies:
@@ -19661,7 +19661,7 @@ snapshots:
'@graphql-tools/utils': 10.8.6(graphql@16.11.0)
auto-bind: 4.0.0
graphql: 16.11.0
tslib: 2.6.2
tslib: 2.6.3
transitivePeerDependencies:
- encoding
@@ -19673,14 +19673,14 @@ snapshots:
graphql: 16.11.0
import-from: 4.0.0
lodash: 4.18.1
tslib: 2.6.2
tslib: 2.6.3
'@graphql-codegen/schema-ast@4.1.0(graphql@16.11.0)':
dependencies:
'@graphql-codegen/plugin-helpers': 5.1.0(graphql@16.11.0)
'@graphql-tools/utils': 10.8.6(graphql@16.11.0)
graphql: 16.11.0
tslib: 2.6.2
tslib: 2.6.3
'@graphql-codegen/typed-document-node@5.1.1(encoding@0.1.13)(graphql@16.11.0)':
dependencies:
@@ -19689,7 +19689,7 @@ snapshots:
auto-bind: 4.0.0
change-case-all: 1.0.15
graphql: 16.11.0
tslib: 2.6.2
tslib: 2.6.3
transitivePeerDependencies:
- encoding
@@ -19701,7 +19701,7 @@ snapshots:
auto-bind: 4.0.0
graphql: 16.11.0
graphql-sock: 1.0.1(graphql@16.11.0)
tslib: 2.6.2
tslib: 2.6.3
transitivePeerDependencies:
- encoding
@@ -19714,7 +19714,7 @@ snapshots:
auto-bind: 4.0.0
graphql: 16.11.0
graphql-sock: 1.0.1(graphql@16.11.0)
tslib: 2.6.2
tslib: 2.6.3
transitivePeerDependencies:
- encoding
@@ -19725,7 +19725,7 @@ snapshots:
'@graphql-codegen/visitor-plugin-common': 5.8.0(encoding@0.1.13)(graphql@16.11.0)
auto-bind: 4.0.0
graphql: 16.11.0
tslib: 2.6.2
tslib: 2.6.3
transitivePeerDependencies:
- encoding
@@ -19741,7 +19741,7 @@ snapshots:
graphql: 16.11.0
graphql-tag: 2.12.6(graphql@16.11.0)
parse-filepath: 1.0.2
tslib: 2.6.2
tslib: 2.6.3
transitivePeerDependencies:
- encoding
@@ -20045,7 +20045,7 @@ snapshots:
'@har-sdk/core': 1.4.5
json-pointer: 0.6.2
randexp: 0.5.3
tslib: 2.6.2
tslib: 2.8.1
'@hcaptcha/loader@2.0.0': {}
@@ -34997,7 +34997,7 @@ snapshots:
minimist: 1.2.8
strip-bom: 3.0.0
tslib@2.6.2: {}
tslib@2.6.3: {}
tslib@2.8.1: {}