mirror of
https://github.com/supabase/supabase.git
synced 2026-10-11 12:25:05 +03:00
## Problem Project cards on the home page showed resource exhaustion warnings twice: once as a badge in the card header, and again as an alert in the card footer. This created a confusing, redundant UI as seen when a project has disk IO, CPU, or other resource warnings active. ## Fix Removed `resourceWarnings` from the footer `ProjectCardStatus` render in `ProjectCard.tsx`. Resource exhaustion state now only appears as the header badge (which already shows a tooltip with the description on hover). Project status indicators such as paused or restarting still appear in the footer since those do not depend on resource warnings. Also removed the dead `showResourceExhaustionWarnings = false` flag from `ProjectCardStatus.tsx`, which was hardcoded to false and only gated description text that was no longer reachable. ## How to test - Navigate to the org home page with a project that has an active resource warning (disk IO, disk space, CPU, memory, or read-only mode). - Confirm the warning badge appears in the card header with the correct color (warning or critical). - Confirm no duplicate alert appears in the card footer area. - Confirm that paused or restarting projects still show the status alert in the footer. - Confirm the table view still shows the badge correctly in the status column. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit ## Release Notes **Style** - Project status information now displays exclusively in the project card footer, removing redundant header display for a cleaner interface. - Simplified resource warning notification logic for more consistent and straightforward warning presentation. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
157 lines
6.4 KiB
TypeScript
157 lines
6.4 KiB
TypeScript
import { Copy, Github, MoreVertical, Settings } from 'lucide-react'
|
|
import { useRouter } from 'next/router'
|
|
import InlineSVG from 'react-inlinesvg'
|
|
import { toast } from 'sonner'
|
|
import {
|
|
Button,
|
|
copyToClipboard,
|
|
DropdownMenu,
|
|
DropdownMenuContent,
|
|
DropdownMenuItem,
|
|
DropdownMenuTrigger,
|
|
} from 'ui'
|
|
|
|
import { inferProjectStatus } from './ProjectCard.utils'
|
|
import { ProjectCardStatus } from './ProjectCardStatus'
|
|
import CardButton from '@/components/ui/CardButton'
|
|
import { ComputeBadgeWrapper } from '@/components/ui/ComputeBadgeWrapper'
|
|
import type { IntegrationProjectConnection } from '@/data/integrations/integrations.types'
|
|
import { ProjectIndexPageLink } from '@/data/prefetchers/project.$ref'
|
|
import { getComputeSize, OrgProject } from '@/data/projects/org-projects-infinite-query'
|
|
import type { ResourceWarning } from '@/data/usage/resource-warnings-query'
|
|
import { useCustomContent } from '@/hooks/custom-content/useCustomContent'
|
|
import { useIsFeatureEnabled } from '@/hooks/misc/useIsFeatureEnabled'
|
|
import { BASE_PATH } from '@/lib/constants'
|
|
import type { Organization } from '@/types'
|
|
|
|
export interface ProjectCardProps {
|
|
slug?: string
|
|
project: OrgProject
|
|
organization?: Organization
|
|
rewriteHref?: string
|
|
githubIntegration?: IntegrationProjectConnection
|
|
vercelIntegration?: IntegrationProjectConnection
|
|
resourceWarnings?: ResourceWarning
|
|
}
|
|
|
|
export const ProjectCard = ({
|
|
slug,
|
|
project,
|
|
rewriteHref,
|
|
githubIntegration,
|
|
vercelIntegration,
|
|
resourceWarnings,
|
|
}: ProjectCardProps) => {
|
|
const router = useRouter()
|
|
const { name, ref: projectRef } = project
|
|
|
|
const { infraAwsNimbusLabel } = useCustomContent(['infra:aws_nimbus_label'])
|
|
const providerLabel =
|
|
project.cloud_provider === 'AWS_NIMBUS' ? infraAwsNimbusLabel : project.cloud_provider
|
|
|
|
const desc = `${providerLabel} | ${project.region}`
|
|
|
|
const { projectHomepageShowInstanceSize } = useIsFeatureEnabled([
|
|
'project_homepage:show_instance_size',
|
|
])
|
|
|
|
const isGithubIntegrated = githubIntegration !== undefined
|
|
const isVercelIntegrated = vercelIntegration !== undefined
|
|
const githubRepository = githubIntegration?.metadata.name ?? undefined
|
|
const projectStatus = inferProjectStatus(project.status)
|
|
|
|
return (
|
|
<>
|
|
<li className="list-none h-min">
|
|
<CardButton
|
|
linkHref={rewriteHref ? rewriteHref : `/project/${projectRef}`}
|
|
className="h-44 !px-0 group pt-5 pb-0 overflow-hidden relative"
|
|
hideChevron
|
|
title={
|
|
<div className="w-full flex flex-col gap-y-4 justify-between px-5">
|
|
<div className="flex flex-col gap-y-0.5 relative">
|
|
<div className="flex items-center justify-between">
|
|
<h5 className="text-sm flex-shrink truncate pr-5">{name}</h5>
|
|
<div onClick={(e) => e.preventDefault()}>
|
|
<DropdownMenu>
|
|
<DropdownMenuTrigger asChild>
|
|
<Button
|
|
type="text"
|
|
icon={<MoreVertical size={14} />}
|
|
className="w-6 h-6 px-0"
|
|
onClick={(e) => {
|
|
e.stopPropagation()
|
|
e.preventDefault()
|
|
}}
|
|
onPointerDown={(e) => e.stopPropagation()}
|
|
/>
|
|
</DropdownMenuTrigger>
|
|
<DropdownMenuContent align="end" className="w-48">
|
|
<DropdownMenuItem
|
|
className="gap-x-2"
|
|
onClick={(e) => {
|
|
e.stopPropagation()
|
|
copyToClipboard(projectRef)
|
|
toast.success('Copied project ID to clipboard')
|
|
}}
|
|
>
|
|
<Copy size={14} />
|
|
<span>Copy project ID</span>
|
|
</DropdownMenuItem>
|
|
<DropdownMenuItem
|
|
className="gap-x-2"
|
|
onClick={(e) => {
|
|
e.stopPropagation()
|
|
router.push(`/project/${projectRef}/settings/general`)
|
|
}}
|
|
>
|
|
<Settings size={14} />
|
|
<span>Settings</span>
|
|
</DropdownMenuItem>
|
|
</DropdownMenuContent>
|
|
</DropdownMenu>
|
|
</div>
|
|
</div>
|
|
<p className="text-sm text-foreground-lighter">{desc}</p>
|
|
</div>
|
|
<div className="flex items-center gap-x-1.5 relative overflow-hidden">
|
|
{project.status !== 'INACTIVE' && projectHomepageShowInstanceSize && (
|
|
<ComputeBadgeWrapper
|
|
slug={slug}
|
|
projectRef={project.ref}
|
|
cloudProvider={project.cloud_provider}
|
|
computeSize={getComputeSize(project)}
|
|
resourceWarnings={resourceWarnings}
|
|
badgeClassName="text-[10px] leading-none tracking-[0.07em]"
|
|
/>
|
|
)}
|
|
{isVercelIntegrated && (
|
|
<div className="bg-surface-100 w-5 h-5 p-1 border border-strong rounded-md flex items-center justify-center text-black dark:text-white">
|
|
<InlineSVG
|
|
src={`${BASE_PATH}/img/icons/vercel-icon.svg`}
|
|
title="Vercel Icon"
|
|
className="w-3"
|
|
/>
|
|
</div>
|
|
)}
|
|
{isGithubIntegrated && (
|
|
<div className="bg-surface-100 flex items-center gap-x-0.5 h-5 pr-1 border border-strong rounded-md min-w-0">
|
|
<div className="w-5 h-5 p-1 flex items-center justify-center shrink-0">
|
|
<Github size={12} strokeWidth={1.5} />
|
|
</div>
|
|
<p className="text-xs text-foreground-light truncate">{githubRepository}</p>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
}
|
|
footer={
|
|
<ProjectCardStatus projectStatus={projectStatus} resourceWarnings={resourceWarnings} />
|
|
}
|
|
containerElement={<ProjectIndexPageLink projectRef={projectRef} />}
|
|
/>
|
|
</li>
|
|
</>
|
|
)
|
|
}
|