diff --git a/apps/studio/components/interfaces/BranchManagement/BranchPanels.tsx b/apps/studio/components/interfaces/BranchManagement/BranchPanels.tsx
index f2a1cf2035e..425e4b246ad 100644
--- a/apps/studio/components/interfaces/BranchManagement/BranchPanels.tsx
+++ b/apps/studio/components/interfaces/BranchManagement/BranchPanels.tsx
@@ -1,7 +1,14 @@
import { useParams } from 'common'
import dayjs from 'dayjs'
+import { GitPullRequest } from 'lucide-react'
import Link from 'next/link'
import { PropsWithChildren, ReactNode } from 'react'
+import { useInView } from 'react-intersection-observer'
+
+import ShimmeringLoader from 'components/ui/ShimmeringLoader'
+import { useBranchQuery } from 'data/branches/branch-query'
+import { Branch } from 'data/branches/branches-query'
+import { GitHubPullRequest } from 'data/integrations/integrations-github-pull-requests-query'
import {
Badge,
Button,
@@ -15,11 +22,7 @@ import {
IconShield,
IconTrash,
} from 'ui'
-
-import ShimmeringLoader from 'components/ui/ShimmeringLoader'
-import { Branch } from 'data/branches/branches-query'
-import { GitHubPullRequest } from 'data/integrations/integrations-github-pull-requests-query'
-import { GitPullRequest } from 'lucide-react'
+import BranchStatusBadge from './BranchStatusBadge'
interface BranchManagementSectionProps {
header: string
@@ -86,8 +89,8 @@ export const BranchRow = ({
generateCreatePullRequestURL,
onSelectDeleteBranch,
}: BranchRowProps) => {
- const { ref } = useParams()
- const isActive = ref === branch?.project_ref
+ const { ref: projectRef } = useParams()
+ const isActive = projectRef === branch?.project_ref
const daysFromNow = dayjs().diff(dayjs(branch.updated_at), 'day')
const formattedTimeFromNow = dayjs(branch.updated_at).fromNow()
@@ -96,8 +99,23 @@ export const BranchRow = ({
const createPullRequestURL =
generateCreatePullRequestURL?.(branch.git_branch) ?? 'https://github.com'
+ const { ref, inView } = useInView()
+ const { data } = useBranchQuery(
+ { projectRef, id: branch.id },
+ {
+ enabled: inView,
+ refetchInterval(data) {
+ if (data?.status !== 'ACTIVE_HEALTHY') {
+ return 1000 * 3 // 3 seconds
+ }
+
+ return false
+ },
+ }
+ )
+
return (
-
+
{isActive &&
Current}
+ {data?.status !== undefined &&
}
{daysFromNow > 1 ? `Updated on ${formattedUpdatedAt}` : `Updated ${formattedTimeFromNow}`}
@@ -155,7 +174,7 @@ export const BranchRow = ({
} className="px-1" />
-
+
Change production branch
diff --git a/apps/studio/components/interfaces/BranchManagement/BranchStatusBadge.tsx b/apps/studio/components/interfaces/BranchManagement/BranchStatusBadge.tsx
new file mode 100644
index 00000000000..091c2a6bc70
--- /dev/null
+++ b/apps/studio/components/interfaces/BranchManagement/BranchStatusBadge.tsx
@@ -0,0 +1,46 @@
+import { WarningIcon } from 'components/ui/Icons'
+import { BranchData } from 'data/branches/branch-query'
+import { ClockIcon } from 'lucide-react'
+import { Badge } from 'ui'
+
+type Status = BranchData['status']
+
+export interface BranchStatusBadgeProps {
+ status: Status
+}
+
+const UNHEALTHY_STATUES: Status[] = ['ACTIVE_UNHEALTHY', 'INIT_FAILED', 'UNKNOWN']
+const WAITING_STATUSES: Status[] = ['COMING_UP', 'GOING_DOWN', 'PAUSING', 'RESTORING', 'UPGRADING']
+
+const STATUS_TO_LABEL: Record = {
+ ACTIVE_HEALTHY: 'Healthy',
+ ACTIVE_UNHEALTHY: 'Unhealthy',
+ INIT_FAILED: 'Init failed',
+ UNKNOWN: 'Unknown',
+ COMING_UP: 'Coming up',
+ GOING_DOWN: 'Going down',
+ INACTIVE: 'Inactive',
+ PAUSING: 'Pausing',
+ REMOVED: 'Removed',
+ RESTORING: 'Restoring',
+ UPGRADING: 'Upgrading',
+}
+
+const BranchStatusBadge = ({ status }: BranchStatusBadgeProps) => {
+ if (status === 'ACTIVE_HEALTHY') {
+ return null
+ }
+
+ const isUnhealthy = UNHEALTHY_STATUES.includes(status)
+ const isWaiting = WAITING_STATUSES.includes(status)
+
+ return (
+
+ {isUnhealthy && }
+ {isWaiting && }
+ {STATUS_TO_LABEL[status]}
+
+ )
+}
+
+export default BranchStatusBadge
diff --git a/apps/studio/data/branches/branch-query.ts b/apps/studio/data/branches/branch-query.ts
new file mode 100644
index 00000000000..5b40d9f8178
--- /dev/null
+++ b/apps/studio/data/branches/branch-query.ts
@@ -0,0 +1,38 @@
+import { useQuery, UseQueryOptions } from '@tanstack/react-query'
+
+import { get, handleError } from 'data/fetchers'
+import { ResponseError } from 'types'
+import { branchKeys } from './keys'
+
+export type BranchVariables = {
+ projectRef?: string
+ id?: string
+}
+
+export async function getBranch({ id }: BranchVariables, signal?: AbortSignal) {
+ if (!id) throw new Error('id is required')
+
+ const { data, error } = await get(`/v1/branches/{branch_id}`, {
+ params: { path: { branch_id: id } },
+ signal,
+ })
+ if (error) handleError(error)
+
+ return data
+}
+
+export type BranchData = Awaited>
+export type BranchError = ResponseError
+
+export const useBranchQuery = (
+ { projectRef, id }: BranchVariables,
+ { enabled = true, ...options }: UseQueryOptions = {}
+) =>
+ useQuery(
+ branchKeys.detail(projectRef, id),
+ ({ signal }) => getBranch({ id }, signal),
+ {
+ enabled: enabled && typeof id !== 'undefined',
+ ...options,
+ }
+ )
diff --git a/apps/studio/data/branches/keys.ts b/apps/studio/data/branches/keys.ts
index 76180f83f72..85ce513fd32 100644
--- a/apps/studio/data/branches/keys.ts
+++ b/apps/studio/data/branches/keys.ts
@@ -1,4 +1,5 @@
export const branchKeys = {
list: (projectRef: string | undefined) => ['projects', projectRef, 'branches'] as const,
- detail: (id: string | undefined) => ['branches', id] as const,
+ detail: (projectRef: string | undefined, id: string | undefined) =>
+ ['projects', projectRef, 'branches', id] as const,
}