diff --git a/studio/components/interfaces/BillingV2/Subscription/Subscription.tsx b/studio/components/interfaces/BillingV2/Subscription/Subscription.tsx
index 655ee5d6210..b228c80fcee 100644
--- a/studio/components/interfaces/BillingV2/Subscription/Subscription.tsx
+++ b/studio/components/interfaces/BillingV2/Subscription/Subscription.tsx
@@ -6,7 +6,6 @@ import SubscriptionTier from './Tier/SubscriptionTier'
import { SUBSCRIPTION_PANEL_KEYS, useSubscriptionPageStateSnapshot } from 'state/subscription-page'
import { useSelectedOrganization } from 'hooks'
import { useEffect } from 'react'
-import ProjectBackupsStore from 'stores/project/ProjectBackupsStore'
export interface SubscriptionProps {}
@@ -51,13 +50,15 @@ const Subscription = ({}: SubscriptionProps) => {
}
}, [router, organization?.slug, isOrgBilling])
+ useEffect(() => {
+ if (panel && typeof panel === 'string' && allowedValues.includes(panel)) {
+ snap.setPanelKey(panel as SUBSCRIPTION_PANEL_KEYS)
+ }
+ }, [panel])
+
// No need to bother rendering, we'll redirect anyway
if (isOrgBilling) return null
- if (panel && typeof panel === 'string' && allowedValues.includes(panel)) {
- snap.setPanelKey(panel as SUBSCRIPTION_PANEL_KEYS)
- }
-
return (
<>
diff --git a/studio/components/interfaces/Settings/Addons/ComputeInstanceSidePanel.tsx b/studio/components/interfaces/Settings/Addons/ComputeInstanceSidePanel.tsx
index c8c0a009d21..148afc6d7f9 100644
--- a/studio/components/interfaces/Settings/Addons/ComputeInstanceSidePanel.tsx
+++ b/studio/components/interfaces/Settings/Addons/ComputeInstanceSidePanel.tsx
@@ -3,7 +3,7 @@ import { useQueryClient } from '@tanstack/react-query'
import clsx from 'clsx'
import Link from 'next/link'
import { useRouter } from 'next/router'
-import { useEffect, useState } from 'react'
+import { useEffect, useMemo, useState } from 'react'
import { useParams, useTheme } from 'common'
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
@@ -356,8 +356,8 @@ const ComputeInstanceSidePanel = () => {
{selectedCategory === 'micro' && (
- Your database will use the standard Micro size instance of 2-core {cpuArchitecture} CPU (Shared)
- with 1GB of memory.
+ Your database will use the standard Micro size instance of 2-core {cpuArchitecture}{' '}
+ CPU (Shared) with 1GB of memory.
)}
diff --git a/studio/components/layouts/ProjectLayout/ProjectLayout.tsx b/studio/components/layouts/ProjectLayout/ProjectLayout.tsx
index e2dae22e23c..34248181c50 100644
--- a/studio/components/layouts/ProjectLayout/ProjectLayout.tsx
+++ b/studio/components/layouts/ProjectLayout/ProjectLayout.tsx
@@ -17,6 +17,26 @@ import ProjectPausedState from './ProjectPausedState'
import RestoringState from './RestoringState'
import UpgradingState from './UpgradingState'
+// [Joshen] This is temporary while we unblock users from managing their project
+// if their project is not responding well for any reason. Eventually needs a bit of an overhaul
+const routesToIgnoreProjectDetailsRequest = [
+ '/project/[ref]/settings/general',
+ '/project/[ref]/settings/database',
+ '/project/[ref]/settings/storage',
+ '/project/[ref]/settings/billing/subscription',
+ '/project/[ref]/settings/billing/usage',
+ '/project/[ref]/settings/billing/invoices',
+]
+
+const routesToIgnorePostgrestConnection = [
+ '/project/[ref]/reports',
+ '/project/[ref]/settings/general',
+ '/project/[ref]/settings/database',
+ '/project/[ref]/settings/billing/subscription',
+ '/project/[ref]/settings/billing/usage',
+ '/project/[ref]/settings/billing/invoices',
+]
+
export interface ProjectLayoutProps {
title?: string
isLoading?: boolean
@@ -108,8 +128,14 @@ interface MenuBarWrapperProps {
}
const MenuBarWrapper = ({ isLoading, productMenu, children }: MenuBarWrapperProps) => {
+ const router = useRouter()
const selectedProject = useSelectedProject()
- return <>{!isLoading && productMenu && selectedProject !== undefined ? children : null}>
+ const requiresProjectDetails = !routesToIgnoreProjectDetailsRequest.includes(router.pathname)
+
+ const showMenuBar =
+ !requiresProjectDetails || (requiresProjectDetails && selectedProject !== undefined)
+
+ return <>{!isLoading && productMenu && showMenuBar ? children : null}>
}
interface ContentWrapperProps {
@@ -133,17 +159,9 @@ const ContentWrapper = ({ isLoading, children }: ContentWrapperProps) => {
const selectedProject = useSelectedProject()
const router = useRouter()
- const routesToIgnorePostgrestConnection = [
- '/project/[ref]/reports',
- '/project/[ref]/settings/general',
- '/project/[ref]/settings/database',
- '/project/[ref]/settings/billing/subscription',
- '/project/[ref]/settings/billing/usage',
- '/project/[ref]/settings/billing/invoices',
- ]
-
const requiresDbConnection: boolean = router.pathname !== '/project/[ref]/settings/general'
const requiresPostgrestConnection = !routesToIgnorePostgrestConnection.includes(router.pathname)
+ const requiresProjectDetails = !routesToIgnoreProjectDetailsRequest.includes(router.pathname)
const isProjectUpgrading = selectedProject?.status === PROJECT_STATUS.UPGRADING
const isProjectRestoring = selectedProject?.status === PROJECT_STATUS.RESTORING
@@ -155,7 +173,7 @@ const ContentWrapper = ({ isLoading, children }: ContentWrapperProps) => {
return (
<>
- {isLoading || selectedProject === undefined ? (
+ {isLoading || (requiresProjectDetails && selectedProject === undefined) ? (
) : isProjectUpgrading ? (
@@ -168,7 +186,7 @@ const ContentWrapper = ({ isLoading, children }: ContentWrapperProps) => {
) : requiresDbConnection && isProjectBuilding ? (
) : (
-
{children}
+
{children}
)}
>
)
diff --git a/studio/components/layouts/SettingsLayout/SettingsLayout.tsx b/studio/components/layouts/SettingsLayout/SettingsLayout.tsx
index fa1edfb8c91..61c49d15af0 100644
--- a/studio/components/layouts/SettingsLayout/SettingsLayout.tsx
+++ b/studio/components/layouts/SettingsLayout/SettingsLayout.tsx
@@ -1,18 +1,19 @@
-import { FC, ReactNode, useEffect } from 'react'
+import { useFlag, useSelectedOrganization, useSelectedProject, useStore, withAuth } from 'hooks'
import { observer } from 'mobx-react-lite'
import { useRouter } from 'next/router'
-import { useFlag, useSelectedOrganization, useSelectedProject, useStore, withAuth } from 'hooks'
+import { PropsWithChildren, useEffect } from 'react'
import { generateSettingsMenu } from './SettingsMenu.utils'
-import ProjectLayout from '../'
+import { useParams } from 'common'
import ProductMenu from 'components/ui/ProductMenu'
+import ProjectLayout from '../'
-interface Props {
+interface SettingsLayoutProps {
title?: string
- children: ReactNode
}
-const SettingsLayout: FC
= ({ title, children }) => {
+const SettingsLayout = ({ title, children }: PropsWithChildren) => {
+ const { ref } = useParams()
const { ui, meta } = useStore()
const project = useSelectedProject()
const organization = useSelectedOrganization()
@@ -26,12 +27,7 @@ const SettingsLayout: FC = ({ title, children }) => {
: router.pathname.split('/')[4]
const isVaultEnabled = useFlag('vaultExtension')
- const menuRoutes = generateSettingsMenu(
- project?.ref as string,
- project,
- isVaultEnabled,
- isOrgBilling
- )
+ const menuRoutes = generateSettingsMenu(ref, project, isVaultEnabled, isOrgBilling)
useEffect(() => {
if (ui.selectedProjectRef) {
diff --git a/studio/components/layouts/SettingsLayout/SettingsMenu.utils.ts b/studio/components/layouts/SettingsLayout/SettingsMenu.utils.ts
index b4abdacdbc8..bf9ebf7cfaf 100644
--- a/studio/components/layouts/SettingsLayout/SettingsMenu.utils.ts
+++ b/studio/components/layouts/SettingsLayout/SettingsMenu.utils.ts
@@ -3,7 +3,7 @@ import { IS_PLATFORM, PROJECT_STATUS } from 'lib/constants'
import { ProductMenuGroup } from 'components/ui/ProductMenu/ProductMenu.types'
export const generateSettingsMenu = (
- ref: string,
+ ref?: string,
project?: ProjectBase,
isVaultEnabled: boolean = false,
isOrgBilling: boolean = false
diff --git a/studio/components/to-be-cleaned/Storage/StorageSettings/StorageSettings.tsx b/studio/components/to-be-cleaned/Storage/StorageSettings/StorageSettings.tsx
index d79d2746bfa..640d1a18aa6 100644
--- a/studio/components/to-be-cleaned/Storage/StorageSettings/StorageSettings.tsx
+++ b/studio/components/to-be-cleaned/Storage/StorageSettings/StorageSettings.tsx
@@ -9,6 +9,7 @@ import { useCheckPermissions, useStore } from 'hooks'
import { IS_PLATFORM } from 'lib/constants'
import { STORAGE_FILE_SIZE_LIMIT_MAX_BYTES, StorageSizeUnits } from './StorageSettings.constants'
import { convertFromBytes, convertToBytes } from './StorageSettings.utils'
+import { GenericSkeletonLoader } from 'components/ui/ShimmeringLoader'
export type StorageSettingsProps = {
projectRef: string | undefined
@@ -27,8 +28,8 @@ const StorageSettings = ({ projectRef }: StorageSettingsProps) => {
if (!data) {
return (
-
-
Loading...
+
+
)
}
diff --git a/studio/components/ui/ProjectUpgradeFailedBanner.tsx b/studio/components/ui/ProjectUpgradeFailedBanner.tsx
index 3e96af454a5..6b109898b0d 100644
--- a/studio/components/ui/ProjectUpgradeFailedBanner.tsx
+++ b/studio/components/ui/ProjectUpgradeFailedBanner.tsx
@@ -15,7 +15,8 @@ const ProjectUpgradeFailedBanner = () => {
const { target_version, status, initiated_at, error } = data?.databaseUpgradeStatus ?? {}
const key = `supabase-upgrade-${ref}-${initiated_at}`
- const isAcknowledged = localStorage?.getItem(key) === 'true' ?? false
+ const isAcknowledged =
+ typeof window !== 'undefined' ? localStorage?.getItem(key) === 'true' ?? false : false
const [showMessage, setShowMessage] = useState(!isAcknowledged)
const isFailed = status === DatabaseUpgradeStatus.Failed
diff --git a/studio/data/projects/project-detail-query.ts b/studio/data/projects/project-detail-query.ts
index 79dd3d9ffba..a64643541cf 100644
--- a/studio/data/projects/project-detail-query.ts
+++ b/studio/data/projects/project-detail-query.ts
@@ -8,16 +8,10 @@ import { projectKeys } from './keys'
export type ProjectDetailVariables = { ref?: string }
export async function getProjectDetail({ ref }: ProjectDetailVariables, signal?: AbortSignal) {
- if (!ref) {
- throw new Error('Project ref is required')
- }
+ if (!ref) throw new Error('Project ref is required')
const data = await get
(`${API_URL}/projects/${ref}`, { signal })
-
- if (!isResponseOk(data)) {
- throw data.error
- }
-
+ if (!isResponseOk(data)) throw data.error
return data
}
diff --git a/studio/pages/project/[ref]/settings/storage.tsx b/studio/pages/project/[ref]/settings/storage.tsx
index 8086374e287..09dd18e9582 100644
--- a/studio/pages/project/[ref]/settings/storage.tsx
+++ b/studio/pages/project/[ref]/settings/storage.tsx
@@ -8,9 +8,6 @@ import { post } from 'lib/common/fetch'
import { API_URL, PROJECT_STATUS } from 'lib/constants'
import { NextPageWithLayout } from 'types'
-/**
- * PageLayout is used to setup layout - as usual it will requires inject global store
- */
const PageLayout: NextPageWithLayout = () => {
const { ref: projectRef } = useParams()
const { project } = useProjectContext()
@@ -21,8 +18,6 @@ const PageLayout: NextPageWithLayout = () => {
}
}, [project])
- if (!project) return
-
return (