Files
Danny WhiteandJoshen Lim 05a45dd1ed feat(studio): rename Replication to Pipelines (#50637)
## What kind of change does this PR introduce?

Feature and docs update.

## What is the current behavior?

The Dashboard lists Pipelines destinations under Database > Replication.
Read replicas have moved to Infrastructure, but the temporary notices
remain on the destinations page and new destination sheet.

Closes PIPE-1021.

## What is the new behavior?

The canonical Dashboard routes are Database > Pipelines, while legacy
Replication list and detail URLs permanently redirect to the equivalent
Pipelines routes. Navigation, command palette, shortcuts, pipeline
links, docs, and current marketing copy use Pipelines. Read-replica
notices and their obsolete dismissal state are removed.

| Before | After |
| --- | --- |
| <img width="1024" height="759" alt="Replication Database Agua Basket
Supabase"
src="https://github.com/user-attachments/assets/53f9f565-1ed1-43e9-a7d9-b66b2a47e948"
/> | <img width="1024" height="759" alt="2540"
src="https://github.com/user-attachments/assets/14ab2d61-d01c-483f-9d4f-0ac286dae159"
/> |

The Management API, pipeline behaviour, replication logs, and Postgres
replication terminology remain unchanged.

## To test

- Open `/project/<ref>/database/pipelines` and confirm the Database
navigation, page header, and pipeline breadcrumb say Pipelines.
- Open
`/project/<ref>/database/replication?source=bookmark#destinations` and a
legacy pipeline detail URL. Confirm each redirects to the matching
Pipelines URL while preserving parameters and fragments.
- From the Pipelines page, open Add destination. Confirm no read-replica
migration notice appears.
- Open the Pipelines guide and confirm its Dashboard steps lead to
Database > Pipelines.

## Before merge

- [ ] Get changelog entry reviewed
https://github.com/supabase/changelog/pull/262 and prepare to merge
simultaneously

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

- **New Features**
- Added dedicated **Database > Pipelines** pages for pipeline lists and
details.
- Added permanent redirects from legacy Replication URLs to their
corresponding Pipelines pages.
- Read replica management links now open **Settings > Infrastructure**.

- **Documentation**
- Updated Pipelines setup, monitoring, troubleshooting, and usage
guidance to reference the current dashboard locations.
  - Updated Realtime guidance to use **Database > Publications**.

- **Updates**
- Renamed dashboard navigation, breadcrumbs, commands, and keyboard
shortcuts from **Replication** to **Pipelines**.
  - Removed the “Read replicas have moved” notification.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
2026-09-23 08:52:07 +10:00

180 lines
6.8 KiB
TypeScript

import { useParams } from 'common'
import Link from 'next/link'
import { useRouter } from 'next/router'
import { useState } from 'react'
import {
Alert,
AlertDescription,
AlertDialog,
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
AlertTitle,
Button,
DialogSection,
DialogSectionSeparator,
WarningIcon,
} from 'ui'
import { BackupsEmpty } from '../BackupsEmpty'
import { BackupsStorageAlert } from '../BackupsStorageAlert'
import type { Timezone } from './PITR.types'
import { getClientTimezone } from './PITR.utils'
import { PITRForm } from './PITRForm'
import PITRStatus from './PITRStatus'
import { FormHeader } from '@/components/ui/Forms/FormHeader'
import { useBackupsQuery } from '@/data/database/backups-query'
import { usePitrRestoreMutation } from '@/data/database/pitr-restore-mutation'
import { useSetProjectStatus } from '@/data/projects/project-detail-query'
import { useReadReplicasQuery } from '@/data/read-replicas/replicas-query'
import { PROJECT_STATUS } from '@/lib/constants'
export const PITRSelection = () => {
const router = useRouter()
const { ref } = useParams()
const { data: backups } = useBackupsQuery({ projectRef: ref })
const { data: databases } = useReadReplicasQuery({ projectRef: ref })
const { setProjectStatus } = useSetProjectStatus()
const [showConfiguration, setShowConfiguration] = useState(false)
const [showConfirmation, setShowConfirmation] = useState(false)
const [selectedTimezone, setSelectedTimezone] = useState<Timezone>(getClientTimezone())
const [selectedRecoveryPoint, setSelectedRecoveryPoint] = useState<{
selectedTimezone: Timezone
recoveryTimeTargetUnix: number
recoveryTimeString: string
recoveryTimeStringUtc: string
}>()
const hasReadReplicas = (databases ?? []).length > 1
const { mutateAsync: restoreFromPitr } = usePitrRestoreMutation({
onSuccess: (_, variables) => {
setTimeout(() => {
setShowConfirmation(false)
setProjectStatus({ ref: variables.ref, status: PROJECT_STATUS.RESTORING })
router.push(`/project/${variables.ref}`)
}, 3000)
},
})
const { earliestPhysicalBackupDateUnix, latestPhysicalBackupDateUnix } =
backups?.physicalBackupData ?? {}
const hasNoBackupsAvailable = !earliestPhysicalBackupDateUnix || !latestPhysicalBackupDateUnix
const onConfirmRestore = async () => {
if (!ref) return console.error('Project ref is required')
if (!selectedRecoveryPoint?.recoveryTimeTargetUnix)
return console.error('Recovery time target unix is required')
await restoreFromPitr({
ref,
recovery_time_target_unix: selectedRecoveryPoint.recoveryTimeTargetUnix,
})
}
return (
<>
<FormHeader
title="Restore your database from a backup"
description="Database changes are watched and recorded, so that you can restore your database to any point in time"
/>
<BackupsStorageAlert />
{hasNoBackupsAvailable ? (
<BackupsEmpty />
) : (
<>
{hasReadReplicas && (
<Alert variant="warning">
<WarningIcon />
<AlertTitle>
Unable to restore from PITR as project has read replicas enabled
</AlertTitle>
<AlertDescription>
You will need to remove all read replicas first from your project's infrastructure
settings prior to starting a PITR restore.
</AlertDescription>
<div className="flex items-center gap-x-2 mt-2">
<Button asChild>
<Link href={`/project/${ref}/settings/infrastructure`}>Manage read replicas</Link>
</Button>
</div>
</Alert>
)}
{!showConfiguration ? (
<PITRStatus
selectedTimezone={selectedTimezone}
onUpdateTimezone={setSelectedTimezone}
onSetConfiguration={() => setShowConfiguration(true)}
/>
) : (
<PITRForm
earliestAvailableBackupUnix={earliestPhysicalBackupDateUnix}
latestAvailableBackupUnix={latestPhysicalBackupDateUnix}
onSubmit={(recoveryPoint) => {
setSelectedRecoveryPoint(recoveryPoint)
setShowConfirmation(true)
}}
/>
)}
</>
)}
<AlertDialog open={showConfirmation} onOpenChange={(open) => setShowConfirmation(open)}>
<AlertDialogContent size="medium">
<AlertDialogHeader>
<AlertDialogTitle>Point in time recovery review</AlertDialogTitle>
<AlertDialogDescription asChild>
<div className="flex flex-col space-y-2">
<p className="text-sm text-foreground-light">Your database will be restored to:</p>
<div className="py-2 flex flex-col gap-3">
<div>
<p className="text-sm font-mono text-foreground-lighter">
{selectedRecoveryPoint?.selectedTimezone.text}
</p>
<p className="text-2xl">{selectedRecoveryPoint?.recoveryTimeString}</p>
</div>
<div>
<p className="text-sm font-mono text-foreground-lighter">(UTC+00:00)</p>
<p className="text-2xl">{selectedRecoveryPoint?.recoveryTimeStringUtc}</p>
</div>
</div>
</div>
</AlertDialogDescription>
<DialogSectionSeparator />
<DialogSection>
<Alert variant="warning">
<WarningIcon />
<AlertTitle>This action cannot be undone, not canceled once started</AlertTitle>
<AlertDescription>
Any changes made to your database after this point in time will be lost. This
includes any changes to your project's storage and authentication.
</AlertDescription>
</Alert>
</DialogSection>
<DialogSectionSeparator />
<DialogSection>
<p className="text-sm text-foreground-light">
Restores may take from a few minutes up to several hours depending on the size of
your database. During this period, your project will not be available, until the
restoration is completed.
</p>
</DialogSection>
<AlertDialogFooter>
<AlertDialogCancel>Cancel</AlertDialogCancel>
<AlertDialogAction variant="warning" onClick={onConfirmRestore}>
I understand, begin restore
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogHeader>
</AlertDialogContent>
</AlertDialog>
</>
)
}