diff --git a/apps/studio/components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/DropAllReplicasConfirmationModal.tsx b/apps/studio/components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/DropAllReplicasConfirmationModal.tsx index f3b973fc212..a56372bfe50 100644 --- a/apps/studio/components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/DropAllReplicasConfirmationModal.tsx +++ b/apps/studio/components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/DropAllReplicasConfirmationModal.tsx @@ -1,18 +1,11 @@ import { useParams } from 'common' import toast from 'react-hot-toast' -import { - AlertDescription_Shadcn_, - AlertTitle_Shadcn_, - Alert_Shadcn_, - IconAlertTriangle, - Modal, -} from 'ui' -import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal' -import { useReadReplicaRemoveMutation } from 'data/read-replicas/replica-remove-mutation' -import { Database, useReadReplicasQuery } from 'data/read-replicas/replicas-query' import { useQueryClient } from '@tanstack/react-query' import { replicaKeys } from 'data/read-replicas/keys' +import { useReadReplicaRemoveMutation } from 'data/read-replicas/replica-remove-mutation' +import { useReadReplicasQuery } from 'data/read-replicas/replicas-query' +import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal' interface DropAllReplicasConfirmationModalProps { visible: boolean @@ -38,20 +31,19 @@ const DropAllReplicasConfirmationModal = ({ const replicas = databases.filter((db) => db.identifier !== projectRef) await Promise.all( replicas.map((db) => - removeReadReplica({ projectRef, identifier: db.identifier, skipInvalidateOnSuccess: true }) + removeReadReplica({ + projectRef, + identifier: db.identifier, + invalidateReplicaQueries: false, + }) ) ) toast.success(`Tearing down all read replicas`) - queryClient.setQueriesData(replicaKeys.list(projectRef), (old: Database[]) => { - return old.filter((db: Database) => db.identifier === projectRef) - }) - queryClient.setQueriesData(replicaKeys.loadBalancers(projectRef), (old: Database[]) => []) - - setTimeout(async () => { - await queryClient.invalidateQueries(replicaKeys.list(projectRef)) - await queryClient.invalidateQueries(replicaKeys.loadBalancers(projectRef)) - }, 5000) + await Promise.all([ + queryClient.invalidateQueries(replicaKeys.list(projectRef)), + queryClient.invalidateQueries(replicaKeys.loadBalancers(projectRef)), + ]) onSuccess() onCancel() diff --git a/apps/studio/components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/DropReplicaConfirmationModal.tsx b/apps/studio/components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/DropReplicaConfirmationModal.tsx index 096b5196991..18b6a21fbb2 100644 --- a/apps/studio/components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/DropReplicaConfirmationModal.tsx +++ b/apps/studio/components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/DropReplicaConfirmationModal.tsx @@ -38,7 +38,11 @@ const DropReplicaConfirmationModal = ({ if (!projectRef) return console.error('Project is required') if (selectedReplica === undefined) return toast.error('No replica selected') - await removeReadReplica({ projectRef, identifier: selectedReplica.identifier }) + await removeReadReplica({ + projectRef, + identifier: selectedReplica.identifier, + invalidateReplicaQueries: true, + }) } return ( diff --git a/apps/studio/components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/InstanceConfiguration.tsx b/apps/studio/components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/InstanceConfiguration.tsx index 3d9d7be27be..e34538d6d05 100644 --- a/apps/studio/components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/InstanceConfiguration.tsx +++ b/apps/studio/components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/InstanceConfiguration.tsx @@ -1,6 +1,6 @@ import { useParams } from 'common' import { partition } from 'lodash' -import { Globe2, Loader2, Network } from 'lucide-react' +import { ChevronDown, Globe2, Loader2, Network } from 'lucide-react' import { useTheme } from 'next-themes' import { useEffect, useMemo, useRef, useState } from 'react' import ReactFlow, { Background, Edge, ReactFlowProvider, useReactFlow } from 'reactflow' @@ -12,7 +12,6 @@ import { DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger, - IconChevronDown, } from 'ui' import AlertError from 'components/ui/AlertError' @@ -24,11 +23,12 @@ import { timeout } from 'lib/helpers' import { useSubscriptionPageStateSnapshot } from 'state/subscription-page' import ComputeInstanceSidePanel from '../../Addons/ComputeInstanceSidePanel' import DeployNewReplicaPanel from './DeployNewReplicaPanel' +import DropAllReplicasConfirmationModal from './DropAllReplicasConfirmationModal' import DropReplicaConfirmationModal from './DropReplicaConfirmationModal' +import { REPLICA_STATUS } from './InstanceConfiguration.constants' import { addRegionNodes, generateNodes, getDagreGraphLayout } from './InstanceConfiguration.utils' import { LoadBalancerNode, PrimaryNode, RegionNode, ReplicaNode } from './InstanceNode' import MapView from './MapView' -import DropAllReplicasConfirmationModal from './DropAllReplicasConfirmationModal' // [Joshen] Just FYI, UI assumes single provider for primary + replicas // [Joshen] Idea to visualize grouping based on region: https://reactflow.dev/examples/layout/sub-flows @@ -38,7 +38,7 @@ const InstanceConfigurationUI = () => { const reactFlow = useReactFlow() const { resolvedTheme } = useTheme() const { ref: projectRef } = useParams() - const numComingUp = useRef() + const numTransition = useRef() const snap = useSubscriptionPageStateSnapshot() const [view, setView] = useState<'flow' | 'map'>('flow') @@ -76,13 +76,21 @@ const InstanceConfigurationUI = () => { { refetchInterval: refetchInterval as any, refetchOnWindowFocus: false, - onSuccess: async (data) => { - const comingUpReplicas = data.filter((db) => db.status === 'COMING_UP') - const hasTransientStatus = comingUpReplicas.length > 0 + onSuccess: async (res) => { + const fixedStatues = [ + REPLICA_STATUS.ACTIVE_HEALTHY, + REPLICA_STATUS.ACTIVE_UNHEALTHY, + REPLICA_STATUS.INIT_READ_REPLICA_FAILED, + ] + const replicasInTransition = res.filter((db) => !fixedStatues.includes(db.status)) + const hasTransientStatus = replicasInTransition.length > 0 // If any replica's status has changed, refetch databases - if (numComingUp.current !== comingUpReplicas.length) { - numComingUp.current = comingUpReplicas.length + if ( + numTransition.current !== replicasInTransition.length || + res.length !== (data ?? []).length + ) { + numTransition.current = replicasInTransition.length await refetchReplicas() setTimeout(() => refetchLoadBalancers(), 2000) } @@ -192,7 +200,7 @@ const InstanceConfigurationUI = () => {