mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 09:25:06 +03:00
feat: branching statuses first pass (#20631)
* feat: branching statuses first pass * handle error * use warning icon
This commit is contained in:
1 parent
1bff39b956
commit
a8ee3a212b
4 files changed
+114
-10
No files matched your search
@@ -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 (
|
||||
<div className="w-full flex items-center justify-between px-6 py-2.5">
|
||||
<div className="w-full flex items-center justify-between px-6 py-2.5" ref={ref}>
|
||||
<div className="flex items-center gap-x-4">
|
||||
<Button
|
||||
asChild
|
||||
@@ -110,6 +128,7 @@ export const BranchRow = ({
|
||||
</Link>
|
||||
</Button>
|
||||
{isActive && <Badge color="slate">Current</Badge>}
|
||||
{data?.status !== undefined && <BranchStatusBadge status={data.status} />}
|
||||
<p className="text-xs text-foreground-lighter">
|
||||
{daysFromNow > 1 ? `Updated on ${formattedUpdatedAt}` : `Updated ${formattedTimeFromNow}`}
|
||||
</p>
|
||||
@@ -155,7 +174,7 @@ export const BranchRow = ({
|
||||
<Button type="text" icon={<IconMoreVertical />} className="px-1" />
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="p-0 w-56" side="bottom" align="end">
|
||||
<Link passHref href={`/project/${ref}/settings/integrations`}>
|
||||
<Link passHref href={`/project/${projectRef}/settings/integrations`}>
|
||||
<DropdownMenuItem asChild className="gap-x-2">
|
||||
<a>Change production branch</a>
|
||||
</DropdownMenuItem>
|
||||
|
||||
@@ -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<Status, string> = {
|
||||
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 (
|
||||
<Badge color={isUnhealthy ? 'red' : 'slate'} className="flex items-center gap-1.5">
|
||||
{isUnhealthy && <WarningIcon className="w-3 h-3" />}
|
||||
{isWaiting && <ClockIcon size={12} />}
|
||||
<span>{STATUS_TO_LABEL[status]}</span>
|
||||
</Badge>
|
||||
)
|
||||
}
|
||||
|
||||
export default BranchStatusBadge
|
||||
@@ -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<ReturnType<typeof getBranch>>
|
||||
export type BranchError = ResponseError
|
||||
|
||||
export const useBranchQuery = <TData = BranchData>(
|
||||
{ projectRef, id }: BranchVariables,
|
||||
{ enabled = true, ...options }: UseQueryOptions<BranchData, BranchError, TData> = {}
|
||||
) =>
|
||||
useQuery<BranchData, BranchError, TData>(
|
||||
branchKeys.detail(projectRef, id),
|
||||
({ signal }) => getBranch({ id }, signal),
|
||||
{
|
||||
enabled: enabled && typeof id !== 'undefined',
|
||||
...options,
|
||||
}
|
||||
)
|
||||
@@ -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,
|
||||
}
|
||||
Reference in new issue
Block a user