mirror of
https://github.com/supabase/supabase.git
synced 2026-09-07 02:20:52 +08:00
## What kind of change does this PR introduce? Studio interface improvement. ## What is the current behavior? Read replica creation uses an oversized sheet, with region selection, eligibility guidance, and pricing all awkwardly competing for space. The cost estimate can briefly show a compute-only subtotal while disk pricing is still loading. ## What is the new behavior? Read replica creation uses a focused, centred dialog with a vertical region field, contextual eligibility guidance, and a separate cost breakdown. Disabled forms omit redundant deployment-location text. The additional monthly cost appears only after both compute and disk pricing inputs are available. | Before | After | | --- | --- | | <img width="1024" height="759" alt="Infrastructure Settings Chives Pantry Supabase" src="https://github.com/user-attachments/assets/afb0a9a6-3575-4d65-98a3-f21b23a032ac" /> | <img width="1024" height="759" alt="Infrastructure Settings Chives Pantry Supabase" src="https://github.com/user-attachments/assets/89fd96f8-8f95-4b88-b1fd-505a261ff9a0" /> | | <img width="1024" height="759" alt="Infrastructure Settings Chisel Toolshed Supabase" src="https://github.com/user-attachments/assets/dd110b3a-6aca-4074-9a69-2dc711f4d1c7" /> | <img width="1024" height="759" alt="Infrastructure Settings Chisel Toolshed Supabase" src="https://github.com/user-attachments/assets/894bbd81-01d5-411e-8279-1bd2e5839cff" /> | | <img width="1024" height="759" alt="Infrastructure Settings Chisel Toolshed Supabase" src="https://github.com/user-attachments/assets/09cbd315-c13d-4987-b274-daf4f91ea10d" /> | <img width="1024" height="759" alt="Infrastructure Settings Chisel Toolshed Supabase" src="https://github.com/user-attachments/assets/a1effb33-1bf2-450a-8cd8-0de8675231c9" /> | ## To test - Open `/project/<ref>/settings/infrastructure` and select **Add read replica** from the section header or empty state. Confirm the dialog opens and closes using Close, Escape, backdrop, and Cancel. - On an eligible project, confirm the pricing note initially reads **Estimated additional cost**, then adds **of $X/month** once pricing loads. **View breakdown** should remain disabled until then. - Change the region and open **View breakdown**. Confirm the monthly cost table has standard row borders and an estimated total. - On a project below Small compute, confirm the region field is disabled, its deployment-location description is hidden, and **Change compute** returns to the compute controls. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Replaced the add read replica sheet with a dialog-based setup experience. * Added region details, eligibility guidance, compute recommendations, and estimated pricing. * Added retry options when pricing information fails to load. * **UI Improvements** * Updated warning messages, documentation links, and action labels. * Improved dialog behavior and deferred data loading until opened. * **Tests** * Expanded coverage for dialog behavior, eligibility warnings, pricing errors, retries, and recommendations. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
96 lines
3.4 KiB
TypeScript
96 lines
3.4 KiB
TypeScript
import { screen } from '@testing-library/react'
|
|
import { HttpResponse } from 'msw'
|
|
import { beforeEach, describe, expect, test, vi } from 'vitest'
|
|
|
|
import { ReadReplicasSection } from '@/components/interfaces/Settings/Infrastructure/ReadReplicas/ReadReplicasSection'
|
|
import type { components } from '@/data/api'
|
|
import { customRender } from '@/tests/lib/custom-render'
|
|
import { addAPIMock } from '@/tests/lib/msw'
|
|
|
|
type DatabaseDetailResponse = components['schemas']['DatabaseDetailResponse']
|
|
type DatabaseStatusResponse = components['schemas']['DatabaseStatusResponse']
|
|
type LoadBalancerDetailResponse = components['schemas']['LoadBalancerDetailResponse']
|
|
|
|
const { mockUseIsFeatureEnabled } = vi.hoisted(() => ({
|
|
mockUseIsFeatureEnabled: vi.fn(() => ({ infrastructureReadReplicas: true })),
|
|
}))
|
|
|
|
vi.mock('@/hooks/misc/useIsFeatureEnabled', () => ({
|
|
useIsFeatureEnabled: mockUseIsFeatureEnabled,
|
|
}))
|
|
vi.mock(
|
|
'@/components/interfaces/Settings/Infrastructure/ReadReplicas/AddReadReplicaDialog',
|
|
() => ({ AddReadReplicaDialog: () => null })
|
|
)
|
|
|
|
const addReplicaListMocks = () => {
|
|
addAPIMock({
|
|
method: 'get',
|
|
path: '/platform/projects/:ref/databases',
|
|
response: () =>
|
|
HttpResponse.json<DatabaseDetailResponse[]>([
|
|
{
|
|
cloud_provider: 'AWS',
|
|
connectionString: 'postgresql://postgres:password@db.default.supabase.co:5432/postgres',
|
|
db_host: 'db.default.supabase.co',
|
|
db_name: 'postgres',
|
|
db_port: 5432,
|
|
db_user: 'postgres',
|
|
identifier: 'default',
|
|
inserted_at: '2026-01-01T00:00:00.000Z',
|
|
region: 'us-east-1',
|
|
restUrl: 'https://default.supabase.co',
|
|
size: 't4g.small',
|
|
status: 'ACTIVE_HEALTHY',
|
|
},
|
|
]),
|
|
})
|
|
addAPIMock({
|
|
method: 'get',
|
|
path: '/platform/projects/:ref/databases-statuses',
|
|
response: () => HttpResponse.json<DatabaseStatusResponse[]>([]),
|
|
})
|
|
addAPIMock({
|
|
method: 'get',
|
|
path: '/platform/projects/:ref/load-balancers',
|
|
response: () => HttpResponse.json<LoadBalancerDetailResponse[]>([]),
|
|
})
|
|
}
|
|
|
|
describe('ReadReplicasSection', () => {
|
|
beforeEach(() => {
|
|
mockUseIsFeatureEnabled.mockReturnValue({ infrastructureReadReplicas: true })
|
|
})
|
|
|
|
test('renders the read replicas section with add CTA and empty state', async () => {
|
|
mockUseIsFeatureEnabled.mockReturnValue({ infrastructureReadReplicas: true })
|
|
addReplicaListMocks()
|
|
|
|
customRender(<ReadReplicasSection onRecommendCompute={vi.fn()} />)
|
|
|
|
expect(await screen.findByText('Read replicas')).toBeInTheDocument()
|
|
expect(await screen.findByText('No read replicas')).toBeInTheDocument()
|
|
expect(screen.getAllByRole('button', { name: /Add read replica/i }).length).toBeGreaterThan(0)
|
|
})
|
|
|
|
test('does not fetch replicas when the feature is disabled', async () => {
|
|
mockUseIsFeatureEnabled.mockReturnValue({ infrastructureReadReplicas: false })
|
|
|
|
let fetchedReplicas = false
|
|
addAPIMock({
|
|
method: 'get',
|
|
path: '/platform/projects/:ref/databases',
|
|
response: () => {
|
|
fetchedReplicas = true
|
|
return HttpResponse.json<DatabaseDetailResponse[]>([])
|
|
},
|
|
})
|
|
|
|
customRender(<ReadReplicasSection onRecommendCompute={vi.fn()} />)
|
|
|
|
expect(screen.queryByText('Read replicas')).not.toBeInTheDocument()
|
|
await new Promise((resolve) => setTimeout(resolve, 50))
|
|
expect(fetchedReplicas).toBe(false)
|
|
})
|
|
})
|