mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 09:25:06 +03:00
Chore/adjust instance node for replicas (#42550)
## Context Replaces the provider name with the region code in the infrastructure settings overview node diagram - The latter is more important, and we don't really specify the cloud provider anywhere in the dashboard <img width="315" height="137" alt="Screenshot 2026-02-05 at 18 43 11" src="https://github.com/user-attachments/assets/bc6f4dab-e9be-4663-ae1e-50e76b517c86" /> Also made the same changes in the upcoming database replication page too in the form of tooltips And swapped the title + description to be more consistent (Top: type of data, bottom: description), same for the table below Before: <img width="737" height="335" alt="image" src="https://github.com/user-attachments/assets/6674564b-e871-4cd9-83a3-e0bfde7a9f83" /> <img width="287" height="354" alt="image" src="https://github.com/user-attachments/assets/f234de68-107b-470d-804a-bd3b1d9ae9dc" /> After: <img width="637" height="350" alt="image" src="https://github.com/user-attachments/assets/03e08d55-43a1-4a16-8be1-11dd7d14fef3" /> <img width="364" height="357" alt="image" src="https://github.com/user-attachments/assets/0e49df5b-68e5-4652-8dca-4d44ebb8c3ab" /> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added region metadata with interactive tooltips across replication and database views. * Actions that modify replicas now refresh the list automatically. * Replication diagram layout updated with increased node spacing and a wider zoom-out range. * **Style** * Destination and replica name/ID display reorganized for clearer, two-line presentation. * BigQuery icon now inherits color from CSS for better visual consistency. * Provider/region labels refined for clearer wording. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Alaister Young <a@alaisteryoung.com>
This commit is contained in:
1 parent
e14a048416
commit
45f96a197f
7 files changed
+61
-60
No files matched your search
@@ -148,12 +148,10 @@ export const DestinationRow = ({ destinationId }: DestinationRowProps) => {
|
||||
<ShimmeringLoader />
|
||||
) : (
|
||||
<div>
|
||||
<p title={destinationName} className="truncate">
|
||||
{destinationName}
|
||||
</p>
|
||||
<p className="text-foreground-lighter">
|
||||
<p>
|
||||
{type} (ID: {pipeline?.id})
|
||||
</p>
|
||||
<p className="text-foreground-lighter">{destinationName}</p>
|
||||
</div>
|
||||
)}
|
||||
</TableCell>
|
||||
|
||||
+20
-12
@@ -1,15 +1,8 @@
|
||||
import { useParams } from 'common'
|
||||
import { Database as DatabaseIcon } from 'icons'
|
||||
import { Loader2, Minus, MoreVertical, RotateCcw, Trash } from 'lucide-react'
|
||||
import Link from 'next/link'
|
||||
import { useMemo, useState } from 'react'
|
||||
|
||||
import { DropReplicaConfirmationModal } from '@/components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/DropReplicaConfirmationModal'
|
||||
import { REPLICA_STATUS } from '@/components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/InstanceConfiguration.constants'
|
||||
import { RestartReplicaConfirmationModal } from '@/components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/RestartReplicaConfirmationModal'
|
||||
import { useReplicationLagQuery } from '@/data/read-replicas/replica-lag-query'
|
||||
import { type Database } from '@/data/read-replicas/replicas-query'
|
||||
import { formatDatabaseID } from '@/data/read-replicas/replicas.utils'
|
||||
import { useParams } from 'common'
|
||||
import { Database as DatabaseIcon } from 'icons'
|
||||
import { AWS_REGIONS } from 'shared-data'
|
||||
import {
|
||||
Badge,
|
||||
@@ -21,9 +14,19 @@ import {
|
||||
DropdownMenuTrigger,
|
||||
TableCell,
|
||||
TableRow,
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
TooltipTrigger,
|
||||
} from 'ui'
|
||||
import { ShimmeringLoader } from 'ui-patterns'
|
||||
|
||||
import { getIsInTransition, getStatusLabel } from './ReadReplicas.utils'
|
||||
import { DropReplicaConfirmationModal } from '@/components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/DropReplicaConfirmationModal'
|
||||
import { REPLICA_STATUS } from '@/components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/InstanceConfiguration.constants'
|
||||
import { RestartReplicaConfirmationModal } from '@/components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/RestartReplicaConfirmationModal'
|
||||
import { useReplicationLagQuery } from '@/data/read-replicas/replica-lag-query'
|
||||
import { type Database } from '@/data/read-replicas/replicas-query'
|
||||
import { formatDatabaseID } from '@/data/read-replicas/replicas.utils'
|
||||
|
||||
interface ReadReplicaRow {
|
||||
replica: Database
|
||||
@@ -51,7 +54,7 @@ export const ReadReplicaRow = ({ replica, onUpdateReplica }: ReadReplicaRow) =>
|
||||
const [showConfirmRestart, setShowConfirmRestart] = useState(false)
|
||||
const [showConfirmDrop, setShowConfirmDrop] = useState(false)
|
||||
|
||||
const regionLabel = Object.values(AWS_REGIONS).find((x) => x.code === region)?.displayName
|
||||
const regionMeta = Object.values(AWS_REGIONS).find((x) => x.code === region)
|
||||
|
||||
const isInTransition = useMemo(() => getIsInTransition({ status }), [status])
|
||||
const statusLabel = useMemo(() => getStatusLabel({ status }), [status])
|
||||
@@ -65,8 +68,13 @@ export const ReadReplicaRow = ({ replica, onUpdateReplica }: ReadReplicaRow) =>
|
||||
|
||||
<TableCell>
|
||||
<div>
|
||||
<p>{regionLabel}</p>
|
||||
<p className="text-foreground-lighter">Read Replica (ID: {formattedId})</p>
|
||||
<p>Read Replica (ID: {formattedId})</p>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<p className="text-foreground-lighter w-fit">{regionMeta?.displayName}</p>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="right">{regionMeta?.code}</TooltipContent>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</TableCell>
|
||||
|
||||
|
||||
+24
-25
@@ -1,6 +1,13 @@
|
||||
import { useParams } from 'common'
|
||||
import { AnalyticsBucket, BigQuery, Database } from 'icons'
|
||||
import { PropsWithChildren, useMemo } from 'react'
|
||||
import { Handle, Position } from 'reactflow'
|
||||
import { AWS_REGIONS } from 'shared-data'
|
||||
import { cn, Tooltip, TooltipContent, TooltipTrigger } from 'ui'
|
||||
|
||||
import { getStatusName } from '../Pipeline.utils'
|
||||
import { getStatusLabel } from '../ReadReplicas/ReadReplicas.utils'
|
||||
import { STATUS_REFRESH_FREQUENCY_MS } from '../Replication.constants'
|
||||
import { useReadReplicasQuery } from '@/data/read-replicas/replicas-query'
|
||||
import { formatDatabaseID } from '@/data/read-replicas/replicas.utils'
|
||||
import { useReplicationDestinationsQuery } from '@/data/replication/destinations-query'
|
||||
@@ -8,13 +15,6 @@ import { useReplicationPipelineStatusQuery } from '@/data/replication/pipeline-s
|
||||
import { useReplicationPipelinesQuery } from '@/data/replication/pipelines-query'
|
||||
import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject'
|
||||
import { BASE_PATH } from '@/lib/constants'
|
||||
import { useParams } from 'common'
|
||||
import { AnalyticsBucket, BigQuery, Database } from 'icons'
|
||||
import { AWS_REGIONS } from 'shared-data'
|
||||
import { cn, Tooltip, TooltipContent, TooltipTrigger } from 'ui'
|
||||
import { getStatusName } from '../Pipeline.utils'
|
||||
import { getStatusLabel } from '../ReadReplicas/ReadReplicas.utils'
|
||||
import { STATUS_REFRESH_FREQUENCY_MS } from '../Replication.constants'
|
||||
|
||||
export const NODE_WIDTH = 480
|
||||
|
||||
@@ -42,18 +42,15 @@ export const PrimaryDatabaseNode = () => {
|
||||
const { data: destinationsData } = useReplicationDestinationsQuery({ projectRef })
|
||||
const hasDestinations = (destinationsData?.destinations ?? []).length > 0
|
||||
|
||||
const regionLabel = Object.values(AWS_REGIONS).find(
|
||||
(x) => x.code === project?.region
|
||||
)?.displayName
|
||||
const region = Object.values(AWS_REGIONS).find((x) => x.code === project?.region)
|
||||
const hasReplication = hasReadReplicas || hasDestinations
|
||||
|
||||
return (
|
||||
<NodeContainer>
|
||||
<div className="flex flex-col gap-y-0.5">
|
||||
<p className="text-sm">Primary Database</p>
|
||||
<p className="text-sm text-foreground-light">
|
||||
{project?.cloud_provider} • {regionLabel}
|
||||
</p>
|
||||
<div className="text-sm flex flex-col gap-y-0.5">
|
||||
<p>Primary Database</p>
|
||||
<p className="text-foreground-light">{region?.displayName}</p>
|
||||
<p className="text-foreground-light">{region?.code}</p>
|
||||
</div>
|
||||
{!!project && (
|
||||
<img
|
||||
@@ -94,9 +91,9 @@ export const ReplicationNode = ({ id }: { id: string }) => {
|
||||
) : type === 'Analytics Bucket' ? (
|
||||
<AnalyticsBucket size={20} className="text-foreground-light" />
|
||||
) : null}
|
||||
<div className="flex flex-col gap-y-0.5">
|
||||
<div className="text-sm flex flex-col gap-y-0.5">
|
||||
<div className="flex items-center">
|
||||
<p className="text-sm">{destination?.name}</p>
|
||||
<p>{type}</p>
|
||||
<Tooltip>
|
||||
<TooltipTrigger>
|
||||
<div className="w-6 h-full flex items-center justify-center">
|
||||
@@ -117,9 +114,8 @@ export const ReplicationNode = ({ id }: { id: string }) => {
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<p className="text-sm text-foreground-light">
|
||||
{type} (ID: {destination?.id})
|
||||
</p>
|
||||
<p className="text-foreground-light">{destination?.name}</p>
|
||||
<p className="text-foreground-light">ID: {destination?.id}</p>
|
||||
</div>
|
||||
<Handle type="target" position={Position.Left} className="opacity-25" />
|
||||
</NodeContainer>
|
||||
@@ -131,9 +127,7 @@ export const ReadReplicaNode = ({ id }: { id: string }) => {
|
||||
const { data: databases = [] } = useReadReplicasQuery({ projectRef })
|
||||
const database = databases.find((x) => x.identifier === id)
|
||||
|
||||
const regionLabel = Object.values(AWS_REGIONS).find(
|
||||
(x) => x.code === database?.region
|
||||
)?.displayName
|
||||
const region = Object.values(AWS_REGIONS).find((x) => x.code === database?.region)
|
||||
const formattedId = formatDatabaseID(database?.identifier ?? '')
|
||||
const statusLabel = useMemo(
|
||||
() => getStatusLabel({ status: database?.status }),
|
||||
@@ -145,7 +139,7 @@ export const ReadReplicaNode = ({ id }: { id: string }) => {
|
||||
<Database size={20} className="text-foreground-light" />
|
||||
<div className="flex flex-col gap-y-0.5">
|
||||
<div className="flex items-center">
|
||||
<p className="text-sm">{regionLabel}</p>
|
||||
<p className="text-sm">Read Replica</p>
|
||||
<Tooltip>
|
||||
<TooltipTrigger>
|
||||
<div className="w-6 h-full flex items-center justify-center">
|
||||
@@ -160,7 +154,12 @@ export const ReadReplicaNode = ({ id }: { id: string }) => {
|
||||
<TooltipContent side="bottom">{statusLabel}</TooltipContent>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<p className="text-sm text-foreground-light">Read Replica (ID: {formattedId})</p>
|
||||
<p className="text-sm text-foreground-light">{region?.displayName}</p>
|
||||
<div className="flex gap-x-2 items-center text-sm text-foreground-light">
|
||||
<span>ID: {formattedId}</span>
|
||||
<span>•</span>
|
||||
<span>{region?.code}</span>
|
||||
</div>
|
||||
</div>
|
||||
<Handle type="target" position={Position.Left} className="opacity-25" />
|
||||
</NodeContainer>
|
||||
|
||||
+2
-1
@@ -1,9 +1,10 @@
|
||||
import dagre from '@dagrejs/dagre'
|
||||
import { Edge, Node, Position } from 'reactflow'
|
||||
|
||||
import { NODE_WIDTH } from './Nodes'
|
||||
|
||||
const NODE_SEP = 0
|
||||
const NODE_ROW_HEIGHT = 160
|
||||
const NODE_ROW_HEIGHT = 200
|
||||
|
||||
export const getDagreGraphLayout = (nodes: Node[], edges: Edge[]) => {
|
||||
const dagreGraph = new dagre.graphlib.Graph()
|
||||
|
||||
@@ -116,7 +116,7 @@ const ReplicationDiagramContent = () => {
|
||||
|
||||
// [Joshen] Odd fix to ensure that react flow snaps back to center when adding nodes
|
||||
await timeout(1)
|
||||
reactFlow.fitView({ maxZoom: 0.9, minZoom: 0.9 })
|
||||
reactFlow.fitView({ minZoom: 0.8, maxZoom: 0.9 })
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
@@ -127,7 +127,7 @@ const ReplicationDiagramContent = () => {
|
||||
<div className="nowheel relative min-h-[350px]">
|
||||
<ReactFlow
|
||||
fitView
|
||||
fitViewOptions={{ minZoom: 0.9, maxZoom: 0.9 }}
|
||||
fitViewOptions={{ minZoom: 0.8, maxZoom: 0.9 }}
|
||||
className="bg"
|
||||
zoomOnPinch={false}
|
||||
zoomOnScroll={false}
|
||||
|
||||
+10
-15
@@ -1,10 +1,4 @@
|
||||
import { PermissionAction } from '@supabase/shared-types/out/constants'
|
||||
import dayjs from 'dayjs'
|
||||
import { Database, DatabaseBackup, HelpCircle, Loader2, MoreVertical } from 'lucide-react'
|
||||
import Link from 'next/link'
|
||||
import { parseAsBoolean, useQueryState } from 'nuqs'
|
||||
import { Handle, NodeProps, Position } from 'reactflow'
|
||||
|
||||
import { useParams } from 'common'
|
||||
import { DropdownMenuItemTooltip } from 'components/ui/DropdownMenuItemTooltip'
|
||||
import SparkBar from 'components/ui/SparkBar'
|
||||
@@ -14,14 +8,20 @@ import {
|
||||
useReadReplicasStatusesQuery,
|
||||
} from 'data/read-replicas/replicas-status-query'
|
||||
import { formatDatabaseID } from 'data/read-replicas/replicas.utils'
|
||||
import dayjs from 'dayjs'
|
||||
import { useCustomContent } from 'hooks/custom-content/useCustomContent'
|
||||
import { useAsyncCheckPermissions } from 'hooks/misc/useCheckPermissions'
|
||||
import { useIsFeatureEnabled } from 'hooks/misc/useIsFeatureEnabled'
|
||||
import { BASE_PATH } from 'lib/constants'
|
||||
import { Database, DatabaseBackup, HelpCircle, Loader2, MoreVertical } from 'lucide-react'
|
||||
import Link from 'next/link'
|
||||
import { parseAsBoolean, useQueryState } from 'nuqs'
|
||||
import { Handle, NodeProps, Position } from 'reactflow'
|
||||
import { useDatabaseSelectorStateSnapshot } from 'state/database-selector'
|
||||
import {
|
||||
Badge,
|
||||
Button,
|
||||
cn,
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
@@ -30,15 +30,15 @@ import {
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
TooltipTrigger,
|
||||
cn,
|
||||
} from 'ui'
|
||||
|
||||
import {
|
||||
ERROR_STATES,
|
||||
INIT_PROGRESS,
|
||||
NODE_SEP,
|
||||
NODE_WIDTH,
|
||||
REPLICA_STATUS,
|
||||
Region,
|
||||
REPLICA_STATUS,
|
||||
} from './InstanceConfiguration.constants'
|
||||
import { formatSeconds } from './InstanceConfiguration.utils'
|
||||
|
||||
@@ -140,7 +140,7 @@ export const PrimaryNode = ({ data }: NodeProps<PrimaryNodeData>) => {
|
||||
<span className="text-sm text-foreground-light">{region.name}</span>
|
||||
</p>
|
||||
<p className="flex items-center gap-x-1">
|
||||
<span className="text-sm text-foreground-light">{providerLabel}</span>
|
||||
<span className="text-sm text-foreground-light">{region.region}</span>
|
||||
{projectHomepageShowInstanceSize && (
|
||||
<>
|
||||
<span className="text-sm text-foreground-light">•</span>
|
||||
@@ -183,13 +183,11 @@ export const PrimaryNode = ({ data }: NodeProps<PrimaryNodeData>) => {
|
||||
export const ReplicaNode = ({ data }: NodeProps<ReplicaNodeData>) => {
|
||||
const {
|
||||
id,
|
||||
provider,
|
||||
region,
|
||||
computeSize,
|
||||
status,
|
||||
inserted_at,
|
||||
onSelectRestartReplica,
|
||||
onSelectResizeReplica,
|
||||
onSelectDropReplica,
|
||||
} = data
|
||||
const { ref } = useParams()
|
||||
@@ -234,9 +232,6 @@ export const ReplicaNode = ({ data }: NodeProps<ReplicaNodeData>) => {
|
||||
] as string[]
|
||||
).includes(status) || initStatus === ReplicaInitializationStatus.InProgress
|
||||
|
||||
const { infraAwsNimbusLabel } = useCustomContent(['infra:aws_nimbus_label'])
|
||||
const providerLabel = provider === 'AWS_NIMBUS' ? infraAwsNimbusLabel : provider
|
||||
|
||||
return (
|
||||
<>
|
||||
<Handle type="target" position={Position.Top} style={{ background: 'transparent' }} />
|
||||
@@ -303,7 +298,7 @@ export const ReplicaNode = ({ data }: NodeProps<ReplicaNodeData>) => {
|
||||
<div className="my-0.5">
|
||||
<p className="text-sm text-foreground-light">{region.name}</p>
|
||||
<p className="flex text-sm text-foreground-light items-center gap-x-1">
|
||||
<span>{providerLabel}</span>
|
||||
<span>{region.region}</span>
|
||||
{projectHomepageShowInstanceSize && !!computeSize && (
|
||||
<>
|
||||
<span>•</span>
|
||||
|
||||
@@ -15,7 +15,7 @@ const BigQuery = createSupabaseIcon('BigQuery', [
|
||||
'path',
|
||||
{
|
||||
d: 'M7.48981 17.898L7.48981 9.65308M10.8368 18.7552L10.8368 7.53063M14.1837 18.0205V12.0204M21 21.0817L16.4286 16.5103M18.7552 10.8776C18.7552 15.2282 15.2282 18.7552 10.8776 18.7552C6.52691 18.7552 3 15.2282 3 10.8776C3 6.52691 6.52691 3 10.8776 3C15.2282 3 18.7552 6.52691 18.7552 10.8776Z',
|
||||
stroke: 'black',
|
||||
stroke: 'currentColor',
|
||||
'stroke-width': '0.975299',
|
||||
'stroke-linecap': 'round',
|
||||
key: 't3k65m',
|
||||
|
||||
Reference in new issue
Block a user