diff --git a/apps/studio/components/interfaces/Database/Replication/Destinations.tsx b/apps/studio/components/interfaces/Database/Replication/Destinations.tsx
index d9e58ccf4d8..462cb4c7125 100644
--- a/apps/studio/components/interfaces/Database/Replication/Destinations.tsx
+++ b/apps/studio/components/interfaces/Database/Replication/Destinations.tsx
@@ -19,7 +19,7 @@ import {
TableHeader,
TableRow,
} from 'ui'
-import { GenericSkeletonLoader } from 'ui-patterns'
+import { Admonition, GenericSkeletonLoader } from 'ui-patterns'
import { Input } from 'ui-patterns/DataInputs/Input'
import { REPLICA_STATUS } from '../../Settings/Infrastructure/InfrastructureConfiguration/InstanceConfiguration.constants'
@@ -43,6 +43,7 @@ import { replicationKeys } from '@/data/replication/keys'
import { fetchReplicationPipelineVersion } from '@/data/replication/pipeline-version-query'
import { useReplicationPipelinesQuery } from '@/data/replication/pipelines-query'
import { useReplicationSourcesQuery } from '@/data/replication/sources-query'
+import { checkLocalETLNotSetUp } from '@/data/replication/utils'
import { useIsFeatureEnabled } from '@/hooks/misc/useIsFeatureEnabled'
import { DOCS_URL } from '@/lib/constants'
import { SHORTCUT_IDS } from '@/state/shortcuts/registry'
@@ -144,7 +145,9 @@ export const Destinations = () => {
pipelines.length === 0
const isLoading = isDestinationsLoading || isDatabasesLoading
- const hasErrorsFetchingData = isDestinationsError || isDatabasesError
+
+ const isLocalETLNotSetUp = checkLocalETLNotSetUp(destinationsError)
+ const hasErrorsFetchingData = (!isLocalETLNotSetUp && isDestinationsError) || isDatabasesError
const openDestinationPanel = () => {
if (!newDestinationDefaultType) return
@@ -270,6 +273,13 @@ export const Destinations = () => {
/>
)}
+ {isLocalETLNotSetUp && (
+
+ )}
+
{isLoading ? (
) : hasReplicas || hasDestinations ? (
diff --git a/apps/studio/components/interfaces/Database/Replication/ReplicationDiagram/index.tsx b/apps/studio/components/interfaces/Database/Replication/ReplicationDiagram/index.tsx
index f90e8741bff..83a9555cee7 100644
--- a/apps/studio/components/interfaces/Database/Replication/ReplicationDiagram/index.tsx
+++ b/apps/studio/components/interfaces/Database/Replication/ReplicationDiagram/index.tsx
@@ -12,6 +12,7 @@ import { timeout } from '@/lib/helpers'
import '@xyflow/react/dist/style.css'
import { SmoothstepEdge } from './Edges'
+import { checkLocalETLNotSetUp } from '@/data/replication/utils'
export const ReplicationDiagram = () => {
return (
@@ -42,10 +43,17 @@ const ReplicationDiagramContent = () => {
[databases, projectRef]
)
- const { data, isSuccess: isSuccessDestinations } = useReplicationDestinationsQuery({
+ const {
+ data,
+ error: destinationsError,
+ isSuccess: isSuccessDestinations,
+ isError: isErrorDestinations,
+ } = useReplicationDestinationsQuery({
projectRef,
})
const destinations = useMemo(() => data?.destinations ?? [], [data])
+ const isLocalETLNotSetUp = checkLocalETLNotSetUp(destinationsError)
+ const skipRenderingDestinations = isErrorDestinations && isLocalETLNotSetUp
const nodes = useMemo(() => {
return [
@@ -103,10 +111,14 @@ const ReplicationDiagramContent = () => {
}
useEffect(() => {
- if (nodes.length > 0 && isSuccessDestinations && isSuccessReplicas) {
+ if (
+ nodes.length > 0 &&
+ (isSuccessDestinations || skipRenderingDestinations) &&
+ isSuccessReplicas
+ ) {
setReactFlow()
}
- }, [nodes, isSuccessDestinations, isSuccessReplicas])
+ }, [nodes, isSuccessDestinations, skipRenderingDestinations, isSuccessReplicas])
return (
diff --git a/apps/studio/data/replication/utils.ts b/apps/studio/data/replication/utils.ts
index bf493328fab..31289a682e7 100644
--- a/apps/studio/data/replication/utils.ts
+++ b/apps/studio/data/replication/utils.ts
@@ -1,6 +1,20 @@
import { MAX_RETRY_FAILURE_COUNT } from '@/data/query-client'
import { ResponseError } from '@/types'
+const isLocal =
+ process.env.NEXT_PUBLIC_ENVIRONMENT !== 'prod' &&
+ process.env.NEXT_PUBLIC_ENVIRONMENT !== 'staging'
+
+export const checkLocalETLNotSetUp = (error: ResponseError | null) => {
+ if (error === null) return false
+
+ const isETLAPINotRunning =
+ error.code === undefined && error.message.includes('API error happened')
+ const isETLNotSetUp =
+ error.code === 503 && error.message.includes('replication API URL is not configured')
+ return isLocal && (isETLAPINotRunning || isETLNotSetUp)
+}
+
export const checkReplicationFeatureFlagRetry = (
failureCount: number,
error: ResponseError
@@ -10,7 +24,9 @@ export const checkReplicationFeatureFlagRetry = (
error.code === 503 &&
error.message.includes('feature flag is required')
- if (isFeatureFlagRequiredError) {
+ const isLocalETLNotSetUp = checkLocalETLNotSetUp(error)
+
+ if (isFeatureFlagRequiredError || isLocalETLNotSetUp) {
return false
}