+
Reach out to the community
+
- Expected response time is based on your billing plan. Pro and Pay as You Go plans are
- prioritized.
+ For other support, including questions on our client libraries, advice, or best
+ practices.
-
+
-
-
-
-
Reach out to the community
-
-
- For other support, including questions on our client libraries, advice, or best
- practices.
-
-
-
-
-
-
+
+
}>
+ GitHub Discussions
+
+
- }
- >
-
}
- >
-
Help
-
-
+
+
)
}
diff --git a/studio/components/layouts/ProjectLayout/LayoutHeader/NotificationsPopover/index.tsx b/studio/components/layouts/ProjectLayout/LayoutHeader/NotificationsPopover/index.tsx
index 1ff8530f549..ebc0348ea3f 100644
--- a/studio/components/layouts/ProjectLayout/LayoutHeader/NotificationsPopover/index.tsx
+++ b/studio/components/layouts/ProjectLayout/LayoutHeader/NotificationsPopover/index.tsx
@@ -12,15 +12,19 @@ import { Fragment, useState } from 'react'
import ConfirmModal from 'components/ui/Dialogs/ConfirmDialog'
import { useNotificationsQuery } from 'data/notifications/notifications-query'
import { getProjectDetail } from 'data/projects/project-detail-query'
-import { invalidateProjectsQuery, setProjectPostgrestStatus } from 'data/projects/projects-query'
+import { setProjectPostgrestStatus } from 'data/projects/projects-query'
import { useStore } from 'hooks'
import { delete_, patch, post } from 'lib/common/fetch'
import { API_URL } from 'lib/constants'
import { Project } from 'types'
-import { Alert, Button, IconArrowRight, IconBell, Popover } from 'ui'
+import { Alert, Button, IconArrowRight, IconBell, IconInbox, Popover } from 'ui'
import NotificationRow from './NotificationRow'
-const NotificationsPopover = () => {
+interface NotificationsPopoverProps {
+ alt?: boolean
+}
+
+const NotificationsPopover = ({ alt = false }: NotificationsPopoverProps) => {
const queryClient = useQueryClient()
const router = useRouter()
const { meta, ui } = useStore()
@@ -35,9 +39,10 @@ const NotificationsPopover = () => {
if (!notifications) return <>>
- const hasNewNotifications = notifications?.some(
+ const newNotifications = notifications?.filter(
(notification) => notification.notification_status === NotificationStatus.New
)
+ const hasNewNotifications = newNotifications.length > 0
const onOpenChange = async (open: boolean) => {
// TODO(alaister): move this to a mutation
@@ -232,21 +237,47 @@ const NotificationsPopover = () => {
>
-
+
+ {hasNewNotifications && (
+ <>
+ {alt ? null : (
+
+ )}
+ >
+ )}
}
+ type={alt ? 'text' : 'default'}
+ className={alt ? 'px-1' : ''}
+ icon={
+ hasNewNotifications ? (
+
+
{newNotifications.length}
+
+ ) : alt ? (
+
+ ) : (
+
+ )
+ }
+ iconRight={
+ hasNewNotifications ? (
+ <>
+ {alt ? (
+
+ ) : (
+
+ )}
+ >
+ ) : null
+ }
>
- {hasNewNotifications && (
-
- )}
diff --git a/studio/components/layouts/ProjectLayout/LayoutHeader/ProjectDropdown.tsx b/studio/components/layouts/ProjectLayout/LayoutHeader/ProjectDropdown.tsx
index 80152718fc4..232e27d29f5 100644
--- a/studio/components/layouts/ProjectLayout/LayoutHeader/ProjectDropdown.tsx
+++ b/studio/components/layouts/ProjectLayout/LayoutHeader/ProjectDropdown.tsx
@@ -1,13 +1,15 @@
import Link from 'next/link'
import { useRouter } from 'next/router'
import { ParsedUrlQuery } from 'querystring'
-import { Button, Dropdown, IconPlus, Popover } from 'ui'
+import { Badge, Button, Dropdown, IconCode, IconPlus, Popover } from 'ui'
import { useProjectsQuery } from 'data/projects/projects-query'
import { useSelectedOrganization, useSelectedProject } from 'hooks'
import { IS_PLATFORM, PROJECT_STATUS } from 'lib/constants'
+import ShimmeringLoader from 'components/ui/ShimmeringLoader'
import { Organization, Project } from 'types'
import { useOrganizationsQuery } from 'data/organizations/organizations-query'
+import { useProjectSubscriptionV2Query } from 'data/subscriptions/project-subscription-v2-query'
// [Fran] the idea is to let users change projects without losing the current page,
// but at the same time we need to redirect correctly between urls that might be
@@ -71,13 +73,23 @@ const ProjectLink = ({
)
}
-const ProjectDropdown = () => {
+const ProjectDropdown = ({ alt }: { alt?: boolean }) => {
const selectedProject = useSelectedProject()
const selectedOrganization = useSelectedOrganization()
- const { data: allProjects } = useProjectsQuery()
+ const { data: allProjects, isLoading: isLoadingProjects } = useProjectsQuery()
const { data: allOrganizations } = useOrganizationsQuery()
const selectedOrganizationSlug = selectedOrganization?.slug
+ const isOrgBilling = !!selectedOrganization?.subscription_id
+ const { data: subscription, isSuccess } = useProjectSubscriptionV2Query(
+ { projectRef: selectedProject?.ref },
+ { enabled: alt && !isOrgBilling }
+ )
+
+ if (isLoadingProjects && alt) {
+ return
+ }
+
return IS_PLATFORM ? (
{
>
}
>
-
) : (
-
- {selectedProject?.name}
+
+ {selectedProject?.name}
)
}
diff --git a/studio/components/layouts/ProjectLayout/NavigationBar/NavigationBar.tsx b/studio/components/layouts/ProjectLayout/NavigationBar/NavigationBar.tsx
index 50bdff1621b..4efb7bf31a4 100644
--- a/studio/components/layouts/ProjectLayout/NavigationBar/NavigationBar.tsx
+++ b/studio/components/layouts/ProjectLayout/NavigationBar/NavigationBar.tsx
@@ -2,7 +2,6 @@ import * as Tooltip from '@radix-ui/react-tooltip'
import { isUndefined } from 'lodash'
import Link from 'next/link'
import { useRouter } from 'next/router'
-import { FC } from 'react'
import { useTheme } from 'common'
import { useParams } from 'common/hooks'
@@ -27,15 +26,13 @@ import {
} from './NavigationBar.utils'
import NavigationIconButton from './NavigationIconButton'
-interface Props {}
-
-const NavigationBar: FC = ({}) => {
+const NavigationBar = ({}) => {
const router = useRouter()
const { isDarkMode, toggleTheme } = useTheme()
const { ref: projectRef } = useParams()
const { project } = useProjectContext()
- const ongoingIncident = useFlag('ongoingIncident')
+ const navLayoutV2 = useFlag('navigationLayoutV2')
const activeRoute = router.pathname.split('/')[3]
const toolRoutes = generateToolRoutes(projectRef, project)
@@ -46,22 +43,23 @@ const NavigationBar: FC = ({}) => {
const { setIsOpen } = useCommandMenu()
return (
-
-
-
-
-
+ {!navLayoutV2 && (
+
+
+
+
+
+ )}
= ({}) => {
link: `/project/${projectRef}`,
}}
/>
-
+
{toolRoutes.map((route) => (
= ({}) => {
/>
))}
-
- {IS_PLATFORM && showCmdkHelper && (
-
-
- setIsOpen(true)}
- className="border-none"
- >
-
-
-
-
-
-
-
-
-
+ {IS_PLATFORM && showCmdkHelper && (
+
+
+ setIsOpen(true)}
+ className="border-none"
>
- {os === 'macos' ? (
-
- ) : (
- CTRL
- )}
- K
-
-
-
-
- )}
-
- {IS_PLATFORM && (
- <>
-
- }>
- Account Preferences
-
-
-
- >
- )}
- Theme
- toggleTheme(e === 'dark')}
- >
- {/* [Joshen] Removing system default for now, needs to be supported in useTheme from common packages */}
- {/* System default */}
- Dark
- Light
-
- >
- }
- >
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+ {os === 'macos' ? (
+
+ ) : (
+
CTRL
+ )}
+
K
+
+
+
+
+ )}
+
+ {IS_PLATFORM && (
+ <>
+
+ }
+ >
+ Account Preferences
+
+
+
+ >
+ )}
+ Theme
+ toggleTheme(e === 'dark')}
+ >
+ {/* [Joshen] Removing system default for now, needs to be supported in useTheme from common packages */}
+ {/* System default */}
+ Dark
+ Light
+
+ >
+ }
+ >
+
+
+
+
+
+
+
+ )}
)
}
diff --git a/studio/components/layouts/ProjectLayout/ProductMenuBar.tsx b/studio/components/layouts/ProjectLayout/ProductMenuBar.tsx
index aac652b82f0..35f9456eb82 100644
--- a/studio/components/layouts/ProjectLayout/ProductMenuBar.tsx
+++ b/studio/components/layouts/ProjectLayout/ProductMenuBar.tsx
@@ -1,18 +1,12 @@
-import { FC, ReactNode } from 'react'
-import { useFlag } from 'hooks'
+import { PropsWithChildren } from 'react'
-interface Props {
+interface ProductMenuBarProps {
title: string
- children: ReactNode
}
-const ProductMenuBar: FC = ({ title, children }) => {
- const ongoingIncident = useFlag('ongoingIncident')
- const maxHeight = ongoingIncident ? 'calc(100vh - 44px)' : '100vh'
-
+const ProductMenuBar = ({ title, children }: PropsWithChildren) => {
return (
= ({ title, children }) => {
>
{title}
- {children}
+
+ {children}
+
)
}
diff --git a/studio/components/layouts/ProjectLayout/ProjectLayout.tsx b/studio/components/layouts/ProjectLayout/ProjectLayout.tsx
index 8d20baea54e..4b23582c1ef 100644
--- a/studio/components/layouts/ProjectLayout/ProjectLayout.tsx
+++ b/studio/components/layouts/ProjectLayout/ProjectLayout.tsx
@@ -16,6 +16,7 @@ import { ProjectContextProvider } from './ProjectContext'
import ProjectPausedState from './ProjectPausedState'
import RestoringState from './RestoringState'
import UpgradingState from './UpgradingState'
+import AppLayout from '../AppLayout/AppLayout'
// [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
@@ -59,61 +60,61 @@ const ProjectLayout = ({
}: PropsWithChildren) => {
const router = useRouter()
const { ref: projectRef } = useParams()
- const ongoingIncident = useFlag('ongoingIncident')
const selectedOrganization = useSelectedOrganization()
const selectedProject = useSelectedProject()
const projectName = selectedProject?.name
const organizationName = selectedOrganization?.name
+ const navLayoutV2 = useFlag('navigationLayoutV2')
+
const isPaused = selectedProject?.status === PROJECT_STATUS.INACTIVE
const ignorePausedState =
router.pathname === '/project/[ref]' || router.pathname.includes('/project/[ref]/settings')
const showPausedState = isPaused && !ignorePausedState
return (
-
-
-
- {title
- ? `${title} | Supabase`
- : selectedTable
- ? `${selectedTable} | ${projectName} | ${organizationName} | Supabase`
- : projectName
- ? `${projectName} | ${organizationName} | Supabase`
- : organizationName
- ? `${organizationName} | Supabase`
- : 'Supabase'}
-
-
-
-
- {/* Left-most navigation side bar to access products */}
- {!hideIconBar &&
}
+
+
+
+
+ {title
+ ? `${title} | Supabase`
+ : selectedTable
+ ? `${selectedTable} | ${projectName} | ${organizationName} | Supabase`
+ : projectName
+ ? `${projectName} | ${organizationName} | Supabase`
+ : organizationName
+ ? `${organizationName} | Supabase`
+ : 'Supabase'}
+
+
+
+
+ {/* Left-most navigation side bar to access products */}
+ {!hideIconBar &&
}
- {/* Product menu bar */}
- {!showPausedState && (
-
- {productMenu}
-
- )}
-
-
- {!hideHeader && }
- {showPausedState ? (
-
- ) : (
- {children}
+ {/* Product menu bar */}
+ {!showPausedState && (
+
+ {productMenu}
+
)}
-
-
-
+
+
+ {!navLayoutV2 && !hideHeader && }
+ {showPausedState ? (
+
+ ) : (
+ {children}
+ )}
+
+
+
+
)
}
@@ -210,44 +211,44 @@ export const ProjectLayoutNonBlocking = ({
const selectedProject = useSelectedProject()
const router = useRouter()
const { ref: projectRef } = useParams()
- const ongoingIncident = useFlag('ongoingIncident')
const isPaused = selectedProject?.status === PROJECT_STATUS.INACTIVE
const ignorePausedState =
router.pathname === '/project/[ref]' || router.pathname.includes('/project/[ref]/settings')
const showPausedState = isPaused && !ignorePausedState
+ const navLayoutV2 = useFlag('navigationLayoutV2')
+
return (
-
-
- {title ? `${title} | Supabase` : 'Supabase'}
-
-
-
-
- {/* Left-most navigation side bar to access products */}
- {!hideIconBar &&
}
+
+
+
+ {title ? `${title} | Supabase` : 'Supabase'}
+
+
+
+
+ {/* Left-most navigation side bar to access products */}
+ {!hideIconBar &&
}
- {/* Product menu bar */}
- {productMenu && !showPausedState && (
-
{productMenu}
- )}
-
-
- {!hideHeader && }
- {showPausedState ? (
-
- ) : (
- children
+ {/* Product menu bar */}
+ {productMenu && !showPausedState && (
+ {productMenu}
)}
-
-
-
+
+
+ {!navLayoutV2 && !hideHeader && }
+ {showPausedState ? (
+
+ ) : (
+ children
+ )}
+
+
+
+
)
}
diff --git a/studio/components/layouts/ProjectSettingsLayout/SettingsLayout.tsx b/studio/components/layouts/ProjectSettingsLayout/SettingsLayout.tsx
new file mode 100644
index 00000000000..2793fa28c80
--- /dev/null
+++ b/studio/components/layouts/ProjectSettingsLayout/SettingsLayout.tsx
@@ -0,0 +1,51 @@
+import { useFlag, useSelectedOrganization, useSelectedProject, useStore, withAuth } from 'hooks'
+import { observer } from 'mobx-react-lite'
+import { useRouter } from 'next/router'
+import { PropsWithChildren, useEffect } from 'react'
+import { generateSettingsMenu } from './SettingsMenu.utils'
+
+import ProductMenu from 'components/ui/ProductMenu'
+import ProjectLayout from '..'
+import { useParams } from 'common'
+
+interface SettingsLayoutProps {
+ title?: string
+}
+
+const SettingsLayout = ({ title, children }: PropsWithChildren) => {
+ const router = useRouter()
+ const { ref } = useParams()
+ const { ui, meta } = useStore()
+ const project = useSelectedProject()
+ const organization = useSelectedOrganization()
+ const isOrgBilling = !!organization?.subscription_id
+
+ // billing pages live under /billing/invoices and /billing/subscription, etc
+ // so we need to pass the [5]th part of the url to the menu
+ const page = router.pathname.includes('billing')
+ ? router.pathname.split('/')[5]
+ : router.pathname.split('/')[4]
+
+ const isVaultEnabled = useFlag('vaultExtension')
+ const menuRoutes = generateSettingsMenu(ref, project, isVaultEnabled, isOrgBilling)
+
+ useEffect(() => {
+ if (ui.selectedProjectRef) {
+ meta.extensions.load()
+ }
+ }, [ui.selectedProjectRef])
+
+ return (
+ }
+ >
+
+ {children}
+
+
+ )
+}
+
+export default withAuth(observer(SettingsLayout))
diff --git a/studio/components/layouts/SettingsLayout/SettingsMenu.utils.ts b/studio/components/layouts/ProjectSettingsLayout/SettingsMenu.utils.ts
similarity index 100%
rename from studio/components/layouts/SettingsLayout/SettingsMenu.utils.ts
rename to studio/components/layouts/ProjectSettingsLayout/SettingsMenu.utils.ts
diff --git a/studio/components/layouts/SettingsLayout/AccountSettingsMenu.tsx b/studio/components/layouts/SettingsLayout/AccountSettingsMenu.tsx
new file mode 100644
index 00000000000..80c3b593dd3
--- /dev/null
+++ b/studio/components/layouts/SettingsLayout/AccountSettingsMenu.tsx
@@ -0,0 +1,28 @@
+import { useRouter } from 'next/router'
+import SettingsMenuItem from './SettingsMenuItem'
+
+const AccountSettingsMenu = () => {
+ const router = useRouter()
+ const accountSettings = [
+ { label: 'Preferences', pathname: `/account/me` },
+ { label: 'Access Tokens', pathname: `/account/tokens` },
+ ]
+
+ return (
+
+
+
Account Settings
+ {accountSettings.map((link) => (
+
+ ))}
+
+
+ )
+}
+
+export default AccountSettingsMenu
diff --git a/studio/components/layouts/SettingsLayout/OrganizationSettingsMenu.tsx b/studio/components/layouts/SettingsLayout/OrganizationSettingsMenu.tsx
new file mode 100644
index 00000000000..ee1ff6fe3d7
--- /dev/null
+++ b/studio/components/layouts/SettingsLayout/OrganizationSettingsMenu.tsx
@@ -0,0 +1,59 @@
+import { useRouter } from 'next/router'
+
+import { useSelectedOrganization } from 'hooks'
+import SettingsMenuItem from './SettingsMenuItem'
+
+const OrganizationSettingsMenu = () => {
+ const router = useRouter()
+ const organization = useSelectedOrganization()
+ const organizationSettings = [
+ { label: 'General', pathname: `/org/[slug]/general` },
+ { label: 'Members', pathname: `/org/[slug]/team` },
+ { label: 'Integrations', pathname: `/org/[slug]/integrations` },
+ { label: 'Billing', pathname: `/org/[slug]/billing` },
+ { label: 'Usage', pathname: `/org/[slug]/usage` },
+ { label: 'Invoices', pathname: `/org/[slug]/invoices` },
+ { label: 'OAuth Apps', pathname: `/org/[slug]/apps` },
+ { label: 'Audit Logs', pathname: `/org/[slug]/audit` },
+ ]
+
+ // const { data: allProjects } = useProjectsQuery()
+ // const projects = allProjects?.filter((project) => project.organization_id === organization?.id)
+
+ return (
+
+
+
Organization
+ {organizationSettings.map((link) => (
+
+ ))}
+
+
+ {/* [Joshen] Hiding below until we figure out a better UX for consolidating settings on projects */}
+ {/*
+
Projects
+
+ {projects?.map((project) => (
+
+ ))}
+
+
+
*/}
+
+ )
+}
+
+export default OrganizationSettingsMenu
diff --git a/studio/components/layouts/SettingsLayout/ProjectSettingsMenuItem.tsx b/studio/components/layouts/SettingsLayout/ProjectSettingsMenuItem.tsx
new file mode 100644
index 00000000000..2132e439e40
--- /dev/null
+++ b/studio/components/layouts/SettingsLayout/ProjectSettingsMenuItem.tsx
@@ -0,0 +1,71 @@
+import { useRouter } from 'next/router'
+import {
+ AccordionContent_Shadcn_,
+ AccordionItem_Shadcn_,
+ AccordionTrigger_Shadcn_,
+ IconChevronRight,
+} from 'ui'
+
+import { useSelectedOrganization } from 'hooks'
+import { Project } from 'types'
+import SettingsMenuItem from './SettingsMenuItem'
+
+interface ProjectSettingsMenuItemProps {
+ project: Project
+}
+
+const ProjectSettingsMenuItem = ({ project }: ProjectSettingsMenuItemProps) => {
+ const router = useRouter()
+ const organization = useSelectedOrganization()
+ const isOrgBilling = !!organization?.subscription_id
+
+ // [Joshen] Links need to be updated once we start implementing these
+ const projectSettings = isOrgBilling
+ ? [
+ { label: 'General', pathname: `/project/[ref]/settings/general` },
+ { label: 'Infrastructure', pathname: `/project/[ref]/settings/infrastructure` },
+ { label: 'Add Ons', pathname: `/project/[ref]/settings/addons` },
+ ]
+ : [
+ { label: 'General', pathname: `/project/[ref]/settings/general` },
+ { label: 'Subscription', pathname: `/project/[ref]/settings/billing/subscription` },
+ { label: 'Usage', pathname: `/project/[ref]/settings/billing/usage` },
+ { label: 'Invoices', pathname: `/project/[ref]/settings/billing/invoices` },
+ ]
+
+ return (
+
+
+
+
+
+
+ {projectSettings.map((link) => {
+ const href = link.pathname.replace('[ref]', project.ref)
+ return (
+
+ )
+ })}
+
+
+
+ )
+}
+
+export default ProjectSettingsMenuItem
diff --git a/studio/components/layouts/SettingsLayout/SettingsLayout.tsx b/studio/components/layouts/SettingsLayout/SettingsLayout.tsx
index 61c49d15af0..81ec13f6e89 100644
--- a/studio/components/layouts/SettingsLayout/SettingsLayout.tsx
+++ b/studio/components/layouts/SettingsLayout/SettingsLayout.tsx
@@ -1,51 +1,30 @@
-import { useFlag, useSelectedOrganization, useSelectedProject, useStore, withAuth } from 'hooks'
-import { observer } from 'mobx-react-lite'
-import { useRouter } from 'next/router'
-import { PropsWithChildren, useEffect } from 'react'
-import { generateSettingsMenu } from './SettingsMenu.utils'
-
+import { PropsWithChildren } from 'react'
+import AppLayout from '../AppLayout/AppLayout'
import { useParams } from 'common'
-import ProductMenu from 'components/ui/ProductMenu'
-import ProjectLayout from '../'
-
-interface SettingsLayoutProps {
- title?: string
-}
-
-const SettingsLayout = ({ title, children }: PropsWithChildren) => {
- const { ref } = useParams()
- const { ui, meta } = useStore()
- const project = useSelectedProject()
- const organization = useSelectedOrganization()
- const isOrgBilling = !!organization?.subscription_id
+import OrganizationSettingsMenu from './OrganizationSettingsMenu'
+import AccountSettingsMenu from './AccountSettingsMenu'
+import { useRouter } from 'next/router'
+const SettingsLayout = ({ children }: PropsWithChildren<{}>) => {
const router = useRouter()
- // billing pages live under /billing/invoices and /billing/subscription, etc
- // so we need to pass the [5]th part of the url to the menu
- const page = router.pathname.includes('billing')
- ? router.pathname.split('/')[5]
- : router.pathname.split('/')[4]
-
- const isVaultEnabled = useFlag('vaultExtension')
- const menuRoutes = generateSettingsMenu(ref, project, isVaultEnabled, isOrgBilling)
-
- useEffect(() => {
- if (ui.selectedProjectRef) {
- meta.extensions.load()
- }
- }, [ui.selectedProjectRef])
+ const { ref, slug } = useParams()
return (
- }
- >
-
- {children}
-
-
+
+
+ {router.pathname !== '/projects' && (
+
+ {slug === undefined && ref === undefined ? (
+
+ ) : (
+
+ )}
+
+ )}
+
{children}
+
+
)
}
-export default withAuth(observer(SettingsLayout))
+export default SettingsLayout
diff --git a/studio/components/layouts/SettingsLayout/SettingsMenuItem.tsx b/studio/components/layouts/SettingsLayout/SettingsMenuItem.tsx
new file mode 100644
index 00000000000..e8bcf9b13a0
--- /dev/null
+++ b/studio/components/layouts/SettingsLayout/SettingsMenuItem.tsx
@@ -0,0 +1,27 @@
+import clsx from 'clsx'
+import Link from 'next/link'
+
+interface SettingsMenuItemProps {
+ href: string
+ label: string
+ isActive: boolean
+}
+
+const SettingsMenuItem = ({ href, label, isActive }: SettingsMenuItemProps) => {
+ return (
+
+ )
+}
+
+export default SettingsMenuItem
diff --git a/studio/components/layouts/TableEditorLayout/TableEditorMenu.tsx b/studio/components/layouts/TableEditorLayout/TableEditorMenu.tsx
index 1e8f7e114e6..7e7190a73e9 100644
--- a/studio/components/layouts/TableEditorLayout/TableEditorMenu.tsx
+++ b/studio/components/layouts/TableEditorLayout/TableEditorMenu.tsx
@@ -2,6 +2,7 @@ import { useMemo, useState } from 'react'
import { noop, partition } from 'lodash'
import { observer } from 'mobx-react-lite'
import {
+ Alert,
Button,
Dropdown,
IconCheck,
@@ -83,7 +84,6 @@ const TableEditorMenu = ({
)
const schemas: PostgresSchema[] = meta.schemas.list()
-
const schema = schemas.find((schema) => schema.name === selectedSchema)
const canCreateTables = useCheckPermissions(PermissionAction.TENANT_SQL_ADMIN_WRITE, 'tables')
@@ -110,6 +110,13 @@ const TableEditorMenu = ({
Loading schemas...