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 (