Files
supabase/apps/studio/components/interfaces/Database/Replication/RestartCostEstimate.tsx
T
Danny White 0b002892d7 refactor(studio): simplify pipeline reset dialogs (#50443)
## What kind of change does this PR introduce?

Studio UI refactor.

## What is the current behavior?

Pipeline table reset dialogs repeat explanatory content and use more
layout than the reset decision needs.

## What is the new behavior?

Simplifies the single-table and batch reset confirmations while
preserving their cost estimate, destructive consequences, and existing
reset mutations.

| Before | After |
| --- | --- |
| <img width="854" height="1090" alt="CleanShot 2026-09-16 at 12 54
36@2x"
src="https://github.com/user-attachments/assets/f9eef09b-89d1-4747-bc4c-e81fb64c584b"
/> | <img width="840" height="742" alt="CleanShot 2026-09-16 at 17 01
11@2x"
src="https://github.com/user-attachments/assets/fa45728c-ec66-45c8-9fef-9d2eb8310d4d"
/> |

This is an independent slice extracted from #49630. The related review
series is this one, #50444, #50445, #50446, then #49630.

## To test

1. Open `/project/<ref>/database/replication` and select a pipeline.
2. Reset one replicated table and confirm the dialog explains that
destination data will be deleted and resynchronised.
3. Choose **Reset all tables** and confirm the batch dialog shows the
same concise treatment.

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

## UI Updates

* **UI Updates**
* Renamed replication “restart” actions to “reset” across dialogs,
buttons, notifications, and cost estimates.
* Updated messaging to clarify whether the pipeline will start or
restart automatically after resetting.
* Added clearer initial-sync guidance for all, some, or none of the
affected tables.
* Improved reset cost estimate messaging, including when no additional
initial-sync charge applies.
* Updated reset dialogs with clearer titles, descriptions, loading
states, and error messages.
  * Disabled reset actions when pipeline status is unavailable.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-17 12:13:51 +10:00

93 lines
3.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { useMemo } from 'react'
import { GenericSkeletonLoader } from 'ui-patterns/ShimmeringLoader'
import {
summarizeTableCopyEstimate,
type ReplicationTableIdentity,
type TableCopyEstimate,
} from './TableSyncCopy.utils'
import { useReplicationCostEstimateQuery } from '@/data/replication/cost-estimate-query'
import { formatBytes, formatCurrency } from '@/lib/helpers'
interface RestartCostEstimateProps {
open: boolean
projectRef?: string
sourceId?: number
publicationName?: string
tables: Pick<ReplicationTableIdentity, 'schema' | 'name'>[]
}
export const calculateRestartCostEstimate = (
estimates: TableCopyEstimate[],
tables: Pick<ReplicationTableIdentity, 'schema' | 'name'>[]
) => summarizeTableCopyEstimate(estimates, tables)
export const RestartCostEstimate = ({
open,
projectRef,
sourceId,
publicationName,
tables,
}: RestartCostEstimateProps) => {
const { data: estimate, isFetching } = useReplicationCostEstimateQuery(
{ projectRef, sourceId, publicationName },
{ enabled: open && tables.length > 0 }
)
const restartEstimate = useMemo(
() =>
estimate === undefined
? undefined
: calculateRestartCostEstimate(estimate.table_copy.tables, tables),
[estimate, tables]
)
return (
<div className="space-y-2 border-t px-5 py-4">
{tables.length === 0 ? (
<div className="flex items-center justify-between gap-x-6">
<div className="min-w-0">
<p className="text-sm font-medium">No additional initial sync charge</p>
<p className="text-xs text-foreground-lighter">
This reset will skip initial sync based on the pipeline’s settings.
</p>
</div>
<span className="shrink-0 font-mono text-lg font-semibold" translate="no">
{formatCurrency(0)}
</span>
</div>
) : isFetching ? (
<GenericSkeletonLoader className="w-full" />
) : restartEstimate?.isComplete ? (
<div className="flex items-center justify-between gap-x-6">
<div className="min-w-0">
<p className="text-sm font-medium">Estimated additional initial sync cost</p>
<p className="text-xs text-foreground-lighter">
Based on an estimated {formatBytes(restartEstimate.estimatedBytes)} of initial sync
data across {tables.length} {tables.length === 1 ? 'table' : 'tables'}
</p>
</div>
<span className="shrink-0 font-mono text-lg font-semibold" translate="no">
{formatCurrency(restartEstimate.estimatedCost)}
{restartEstimate.hasRowFilteredTables ? '*' : null}
</span>
</div>
) : (
<p className="text-sm text-foreground-light">
A cost estimate is unavailable. You can still reset the{' '}
{tables.length === 1 ? 'table' : 'tables'}.
</p>
)}
{restartEstimate?.isComplete && restartEstimate.hasRowFilteredTables && (
<p className="text-xs text-foreground-lighter">
*Row filters can reduce the data processed compared with this estimate.
</p>
)}
{restartEstimate?.isComplete && (
<p className="text-xs text-foreground-lighter">
Quick planning estimate; the final charge is based on successfully processed initial sync
data, which is billed again.
</p>
)}
</div>
)
}