mirror of
https://github.com/supabase/supabase.git
synced 2026-10-07 02:15:05 +03:00
## Context Main fix is to adjust the new home page + connect dialog (and connect sheet) to render the project's custom domain if available <img width="471" height="255" alt="image" src="https://github.com/user-attachments/assets/3a208b2e-bdeb-43f5-a2e7-3495881dbaaa" /> <img width="1065" height="233" alt="image" src="https://github.com/user-attachments/assets/2a7b8f81-8c0b-4803-bf0a-fc16a2f1e0e1" /> ## Changes involved - Created a `useProjectApiUrl` hook that will return the API URL depending if custom domains is available, otherwise default to default project API URL - Refactored all the other places that were manually deriving the project's endpoint - Storage Explorer -> copy URL - Edge Functions - Integrations -> Data API + API Docs - Auth Providers -> Callback URL - Also updated the copy CTA for the addons page - Instead of just "Change xxx", make it a bit more actionable - For add ons with binary states (Custom domains, IPv4) - If not enabled yet, "Enable xxx", otherwise "Toggle xxx" - For PITR - If not enabled yet, "Enable PITR", otherwise "Change recovery duration" - Also added "Edit custom domain" CTA if enabled <img width="1144" height="518" alt="image" src="https://github.com/user-attachments/assets/4f152ea5-0cc7-412c-95e8-ad5bb37c19c3" /> ## To test - [ ] Verify that for a project with custom domain set up, all the affected UI mentioned in the above section look correct
153 lines
5.3 KiB
TypeScript
153 lines
5.3 KiB
TypeScript
import { describe, expect, it } from 'vitest'
|
|
|
|
import { buildEntityMaps, getApiEndpoint } from './DataApi.utils'
|
|
import type { ProjectJsonSchemaPaths } from '@/data/docs/project-json-schema-query'
|
|
import type { LoadBalancer } from '@/data/read-replicas/load-balancers-query'
|
|
import type { Database } from '@/data/read-replicas/replicas-query'
|
|
|
|
const makeDatabase = (
|
|
identifier: string,
|
|
restUrl: string
|
|
): Pick<Database, 'identifier' | 'restUrl'> => ({ identifier, restUrl })
|
|
|
|
const makeLoadBalancer = (endpoint: string): Pick<LoadBalancer, 'endpoint'> => ({ endpoint })
|
|
|
|
describe('getApiEndpoint', () => {
|
|
it('returns custom domain URL when custom domain is active and primary database is selected', () => {
|
|
expect(
|
|
getApiEndpoint({
|
|
selectedDatabaseId: 'project-ref',
|
|
projectRef: 'project-ref',
|
|
resolvedEndpoint: 'https://api.example.com',
|
|
loadBalancers: undefined,
|
|
selectedDatabase: makeDatabase(
|
|
'project-ref',
|
|
'https://project-ref.supabase.co/rest/v1'
|
|
) as Database,
|
|
})
|
|
).toBe('https://api.example.com')
|
|
})
|
|
|
|
it('returns database restUrl when custom domain is active but a replica is selected', () => {
|
|
expect(
|
|
getApiEndpoint({
|
|
selectedDatabaseId: 'replica-1',
|
|
projectRef: 'project-ref',
|
|
resolvedEndpoint: 'https://api.example.com',
|
|
loadBalancers: undefined,
|
|
selectedDatabase: makeDatabase(
|
|
'replica-1',
|
|
'https://replica-1.supabase.co/rest/v1'
|
|
) as Database,
|
|
})
|
|
).toBe('https://replica-1.supabase.co/rest/v1')
|
|
})
|
|
|
|
it('returns load balancer endpoint when load balancer is selected', () => {
|
|
expect(
|
|
getApiEndpoint({
|
|
selectedDatabaseId: 'load-balancer',
|
|
projectRef: 'project-ref',
|
|
resolvedEndpoint: 'https://project-ref.supabase.co',
|
|
loadBalancers: [makeLoadBalancer('https://lb.supabase.co') as LoadBalancer],
|
|
selectedDatabase: undefined,
|
|
})
|
|
).toBe('https://lb.supabase.co')
|
|
})
|
|
|
|
it('returns empty string when load balancer is selected but none exist', () => {
|
|
expect(
|
|
getApiEndpoint({
|
|
selectedDatabaseId: 'load-balancer',
|
|
projectRef: 'project-ref',
|
|
resolvedEndpoint: 'https://project-ref.supabase.co',
|
|
loadBalancers: undefined,
|
|
selectedDatabase: undefined,
|
|
})
|
|
).toBe('')
|
|
})
|
|
|
|
it('returns database restUrl for a replica database selection', () => {
|
|
expect(
|
|
getApiEndpoint({
|
|
selectedDatabaseId: 'replica-2',
|
|
projectRef: 'project-ref',
|
|
resolvedEndpoint: 'https://project-ref.supabase.co',
|
|
loadBalancers: undefined,
|
|
selectedDatabase: makeDatabase(
|
|
'replica-2',
|
|
'https://replica-2.supabase.co/rest/v1'
|
|
) as Database,
|
|
})
|
|
).toBe('https://replica-2.supabase.co/rest/v1')
|
|
})
|
|
})
|
|
|
|
describe('buildEntityMaps', () => {
|
|
it('returns empty maps for undefined paths', () => {
|
|
expect(buildEntityMaps(undefined)).toEqual({ resources: {}, rpcs: {} })
|
|
})
|
|
|
|
it('returns empty maps for empty paths', () => {
|
|
expect(buildEntityMaps({})).toEqual({ resources: {}, rpcs: {} })
|
|
})
|
|
|
|
it('skips the root path', () => {
|
|
const paths: ProjectJsonSchemaPaths = {
|
|
'/': { get: {} as ProjectJsonSchemaPaths[string]['get'] },
|
|
}
|
|
expect(buildEntityMaps(paths)).toEqual({ resources: {}, rpcs: {} })
|
|
})
|
|
|
|
it('classifies non-rpc paths as resources', () => {
|
|
const paths: ProjectJsonSchemaPaths = {
|
|
'/users': { get: {} as ProjectJsonSchemaPaths[string]['get'] },
|
|
'/posts': { get: {} as ProjectJsonSchemaPaths[string]['get'] },
|
|
}
|
|
const result = buildEntityMaps(paths)
|
|
expect(Object.keys(result.resources)).toEqual(['users', 'posts'])
|
|
expect(result.rpcs).toEqual({})
|
|
})
|
|
|
|
it('classifies rpc/ paths as rpcs', () => {
|
|
const paths: ProjectJsonSchemaPaths = {
|
|
'/rpc/my_function': { post: {} as ProjectJsonSchemaPaths[string]['post'] },
|
|
}
|
|
const result = buildEntityMaps(paths)
|
|
expect(result.resources).toEqual({})
|
|
expect(Object.keys(result.rpcs)).toEqual(['my_function'])
|
|
})
|
|
|
|
it('enriches entities with displayName and camelCase', () => {
|
|
const paths: ProjectJsonSchemaPaths = {
|
|
'/user_profiles': { get: {} as ProjectJsonSchemaPaths[string]['get'] },
|
|
'/rpc/get_user_count': { post: {} as ProjectJsonSchemaPaths[string]['post'] },
|
|
}
|
|
const result = buildEntityMaps(paths)
|
|
|
|
expect(result.resources['user_profiles']).toEqual({
|
|
id: 'user_profiles',
|
|
displayName: 'user profiles',
|
|
camelCase: 'userProfiles',
|
|
})
|
|
expect(result.rpcs['get_user_count']).toEqual({
|
|
id: 'get_user_count',
|
|
displayName: 'get user count',
|
|
camelCase: 'getUserCount',
|
|
})
|
|
})
|
|
|
|
it('handles mixed resources and rpcs', () => {
|
|
const paths: ProjectJsonSchemaPaths = {
|
|
'/': { get: {} as ProjectJsonSchemaPaths[string]['get'] },
|
|
'/users': { get: {} as ProjectJsonSchemaPaths[string]['get'] },
|
|
'/rpc/hello': { post: {} as ProjectJsonSchemaPaths[string]['post'] },
|
|
'/posts': { get: {} as ProjectJsonSchemaPaths[string]['get'] },
|
|
'/rpc/goodbye': { post: {} as ProjectJsonSchemaPaths[string]['post'] },
|
|
}
|
|
const result = buildEntityMaps(paths)
|
|
expect(Object.keys(result.resources)).toEqual(['users', 'posts'])
|
|
expect(Object.keys(result.rpcs)).toEqual(['hello', 'goodbye'])
|
|
})
|
|
})
|