diff --git a/apps/studio/components/ui/ResourceExhaustionWarningBanner/ResourceExhaustionWarningBanner.tsx b/apps/studio/components/ui/ResourceExhaustionWarningBanner/ResourceExhaustionWarningBanner.tsx
index f4d00c07d7b..f9162666a3d 100644
--- a/apps/studio/components/ui/ResourceExhaustionWarningBanner/ResourceExhaustionWarningBanner.tsx
+++ b/apps/studio/components/ui/ResourceExhaustionWarningBanner/ResourceExhaustionWarningBanner.tsx
@@ -1,3 +1,4 @@
+import { PermissionAction } from '@supabase/shared-types/out/constants'
import { useParams } from 'common'
import { AlertTriangle, BookOpen, ChartLine, ChevronDown, Sparkles, Wrench } from 'lucide-react'
import Link from 'next/link'
@@ -25,18 +26,32 @@ import {
import { mapComputeSizeNameToAddonVariantId } from '@/components/interfaces/DiskManagement/DiskManagement.utils'
import { RestartProjectDialog } from '@/components/interfaces/ErrorHandling/RestartProjectDialog'
import { SIDEBAR_KEYS } from '@/components/layouts/ProjectLayout/LayoutSidebar/LayoutSidebarProvider'
+import { ButtonTooltip } from '@/components/ui/ButtonTooltip'
import { useResourceWarningsQuery } from '@/data/usage/resource-warnings-query'
+import { useAsyncCheckPermissions } from '@/hooks/misc/useCheckPermissions'
import { useSelectedOrganizationQuery } from '@/hooks/misc/useSelectedOrganization'
import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject'
+import { PROJECT_STATUS } from '@/lib/constants'
import { useTrack } from '@/lib/telemetry/track'
import { useAiAssistantStateSnapshot } from '@/state/ai-assistant-state'
import { useSidebarManagerSnapshot } from '@/state/sidebar-manager-state'
-const RESOURCE_WARNINGS_POLL_INTERVAL = 1000 * 60
+const TRANSITIONAL_PROJECT_STATUSES = [
+ PROJECT_STATUS.RESTARTING,
+ PROJECT_STATUS.RESTORING,
+ PROJECT_STATUS.PAUSING,
+ PROJECT_STATUS.RESIZING,
+ PROJECT_STATUS.UPGRADING,
+ PROJECT_STATUS.COMING_UP,
+]
export const ResourceExhaustionWarningBanner = () => {
const { ref } = useParams()
const [showRestartDialog, setShowRestartDialog] = useState(false)
+ const { can: canRestartProject } = useAsyncCheckPermissions(
+ PermissionAction.INFRA_EXECUTE,
+ 'reboot'
+ )
const router = useRouter()
const { data: organization, isLoading: isOrgLoading } = useSelectedOrganizationQuery()
const { data: project } = useSelectedProjectQuery()
@@ -50,10 +65,7 @@ export const ResourceExhaustionWarningBanner = () => {
const { openSidebar } = useSidebarManagerSnapshot()
const aiSnap = useAiAssistantStateSnapshot()
const track = useTrack()
- const { data: resourceWarnings } = useResourceWarningsQuery(
- { ref: ref },
- { staleTime: RESOURCE_WARNINGS_POLL_INTERVAL, refetchInterval: RESOURCE_WARNINGS_POLL_INTERVAL }
- )
+ const { data: resourceWarnings } = useResourceWarningsQuery({ ref: ref })
// [Joshen Cleanup] JFYI this client side filtering can be cleaned up once BE changes are live which will only return the warnings based on the provided ref
const projectResourceWarnings = (resourceWarnings ?? [])?.find(
(warning) => warning.project === ref
@@ -122,7 +134,12 @@ export const ResourceExhaustionWarningBanner = () => {
// True for a single compute warning, or when all active warnings are compute-related
const isComputeUpgradeMetric = isComputeUpgradeWarning(metric, activeWarnings)
- const isMemoryExhaustion = activeWarnings.includes('memory_and_swap_exhaustion')
+ // A restart cannot help while the project is already moving between states, and firing one
+ // off a stale warning would queue a second reboot on top of the one in flight
+ const isProjectTransitioning =
+ project?.status !== undefined && TRANSITIONAL_PROJECT_STATUSES.includes(project.status)
+ const canRestartDatabase = activeWarnings.includes('memory_and_swap_exhaustion')
+ const showRestartButton = canRestartDatabase && !isProjectTransitioning
const correctionUrl = getResourceWarningCorrectionUrl({
metric,
@@ -268,9 +285,17 @@ export const ResourceExhaustionWarningBanner = () => {
Ask AI Assistant
) : null}
- {isMemoryExhaustion && (
-
+
)}
{correctionUrl !== undefined && (