diff --git a/studio/components/interfaces/Organization/GeneralSettings/GeneralSettings.tsx b/studio/components/interfaces/Organization/GeneralSettings/GeneralSettings.tsx
index a46a2d8d4ed..6aec5f64ec0 100644
--- a/studio/components/interfaces/Organization/GeneralSettings/GeneralSettings.tsx
+++ b/studio/components/interfaces/Organization/GeneralSettings/GeneralSettings.tsx
@@ -71,7 +71,6 @@ const GeneralSettings = observer(() => {
const hasChanges = JSON.stringify(values) !== JSON.stringify(initialValues)
return (
{
>
{!canUpdateOrganization && (
- You need additional permissions to manage your organization's settings
+ You need additional permissions to manage this organization's settings
)}
= ({ project, type = 'danger' }) => {
+const DeleteProjectPanel: FC = ({}) => {
const router = useRouter()
- const { ui, app } = useStore()
+ const { app, ui } = useStore()
+ const project = ui.selectedProject
const [isOpen, setIsOpen] = useState(false)
const [loading, setLoading] = useState(false)
@@ -26,6 +24,8 @@ const DeleteProjectButton: FC = ({ project, type = 'danger' }) => {
}
async function handleDeleteProject() {
+ if (project === undefined) return
+
setLoading(true)
try {
const response = await delete_(`${API_URL}/projects/${project.ref}`)
@@ -42,13 +42,32 @@ const DeleteProjectButton: FC = ({ project, type = 'danger' }) => {
}
}
+ if (project === undefined) return <>>
+
return (
<>
-
-
-
+
}>
+
+
+
+
+ Make sure you have made a backup if you want to keep your data.
+
+
+
+
+
+
+
+
+
= ({ project, type = 'danger' }) => {
)
}
-export default DeleteProjectButton
+export default DeleteProjectPanel
diff --git a/studio/components/interfaces/Settings/General/General.tsx b/studio/components/interfaces/Settings/General/General.tsx
new file mode 100644
index 00000000000..889736d6ace
--- /dev/null
+++ b/studio/components/interfaces/Settings/General/General.tsx
@@ -0,0 +1,89 @@
+import { FC } from 'react'
+import { Form, Input } from '@supabase/ui'
+import { PermissionAction } from '@supabase/shared-types/out/constants'
+
+import { useStore, checkPermissions } from 'hooks'
+import { API_URL } from 'lib/constants'
+import { post } from 'lib/common/fetch'
+import {
+ FormHeader,
+ FormPanel,
+ FormActions,
+ FormSection,
+ FormSectionLabel,
+ FormSectionContent,
+} from 'components/ui/Forms'
+
+interface Props {}
+
+const General: FC = ({}) => {
+ const { app, ui } = useStore()
+ const project = ui.selectedProject
+
+ const formId = 'project-general-settings'
+ const initialValues = { name: project?.name ?? '' }
+ const canUpdateProject = checkPermissions(PermissionAction.SQL_UPDATE, 'postgres.public.projects')
+
+ const onSubmit = async (values: any, { setSubmitting, resetForm }: any) => {
+ const response = await post(`${API_URL}/projects/${project?.ref}/update`, values)
+ if (response.error) {
+ ui.setNotification({
+ category: 'error',
+ message: `Update project failed: ${response.error.message}`,
+ })
+ } else {
+ const { name } = response
+ resetForm({ values: { name }, initialValues: { name } })
+
+ app.onProjectUpdated(response)
+ ui.setNotification({
+ category: 'success',
+ message: 'Successfully saved settings',
+ })
+ }
+ }
+
+ return (
+
+ )
+}
+
+export default General
diff --git a/studio/components/interfaces/Settings/General/Infrastructure/Infrastructure.tsx b/studio/components/interfaces/Settings/General/Infrastructure/Infrastructure.tsx
new file mode 100644
index 00000000000..eab6ab727df
--- /dev/null
+++ b/studio/components/interfaces/Settings/General/Infrastructure/Infrastructure.tsx
@@ -0,0 +1,76 @@
+import { FC } from 'react'
+import { Input } from '@supabase/ui'
+import { observer } from 'mobx-react-lite'
+
+import { useStore, useFlag } from 'hooks'
+import { PRICING_TIER_PRODUCT_IDS } from 'lib/constants'
+import {
+ FormHeader,
+ FormPanel,
+ FormSection,
+ FormSectionLabel,
+ FormSectionContent,
+} from 'components/ui/Forms'
+import PauseProjectButton from './PauseProjectButton'
+import RestartServerButton from './RestartServerButton'
+
+interface Props {}
+
+const Infrastructure: FC = ({}) => {
+ const { ui } = useStore()
+ const isProjectPauseEnabled = useFlag('projectPausing')
+
+ const project = ui.selectedProject
+ const isFreeProject = project?.subscription_tier === PRICING_TIER_PRODUCT_IDS.FREE
+
+ return (
+
+
+
+
+
+
Restart server
+
+
+ Your project will not be available for a few minutes.
+
+
+
+ {project &&
}
+
+
+ {isProjectPauseEnabled && isFreeProject && (
+ <>
+
+
+
+
Pause project
+
+
+ Your project will not be accessible while it is paused.
+
+
+
+ {project && (
+
+ )}
+
+ >
+ )}
+ >
+ }
+ >
+ Configuration}>
+
+
+
+
+
+
+
+ )
+}
+
+export default observer(Infrastructure)
diff --git a/studio/components/interfaces/Settings/General/PauseProjectButton.tsx b/studio/components/interfaces/Settings/General/Infrastructure/PauseProjectButton.tsx
similarity index 60%
rename from studio/components/interfaces/Settings/General/PauseProjectButton.tsx
rename to studio/components/interfaces/Settings/General/Infrastructure/PauseProjectButton.tsx
index 5d19c10b5e0..a925bbd150f 100644
--- a/studio/components/interfaces/Settings/General/PauseProjectButton.tsx
+++ b/studio/components/interfaces/Settings/General/Infrastructure/PauseProjectButton.tsx
@@ -1,9 +1,11 @@
import { FC, useState } from 'react'
import { useRouter } from 'next/router'
import { observer } from 'mobx-react-lite'
+import * as Tooltip from '@radix-ui/react-tooltip'
import { Button, IconPause } from '@supabase/ui'
+import { PermissionAction } from '@supabase/shared-types/out/constants'
-import { useStore } from 'hooks'
+import { checkPermissions, useStore } from 'hooks'
import { post } from 'lib/common/fetch'
import { API_URL, PROJECT_STATUS } from 'lib/constants'
import ConfirmModal from 'components/ui/Dialogs/ConfirmDialog'
@@ -22,6 +24,8 @@ const PauseProjectButton: FC = observer(({ projectRef, projectId }) => {
const openModal = () => setIsModalOpen(true)
const closeModal = () => setIsModalOpen(false)
+ const canReboot = checkPermissions(PermissionAction.INFRA_EXECUTE, 'reboot')
+
const requestPauseProject = async () => {
setLoading(true)
const res = await post(`${API_URL}/projects/${projectRef}/pause`, {})
@@ -45,6 +49,34 @@ const PauseProjectButton: FC = observer(({ projectRef, projectId }) => {
return (
<>
+
+
+ }
+ onClick={openModal}
+ loading={loading}
+ disabled={!canReboot}
+ >
+ Pause Project
+
+
+ {!canReboot && (
+
+
+
+
+ You need additional permissions to pause this project
+
+
+
+ )}
+
= observer(({ projectRef, projectId }) => {
onSelectCancel={closeModal}
onSelectConfirm={requestPauseProject}
/>
- } onClick={openModal} loading={loading}>
- Pause Project
-
>
)
})
diff --git a/studio/components/interfaces/Settings/General/RestartServerButton.tsx b/studio/components/interfaces/Settings/General/Infrastructure/RestartServerButton.tsx
similarity index 59%
rename from studio/components/interfaces/Settings/General/RestartServerButton.tsx
rename to studio/components/interfaces/Settings/General/Infrastructure/RestartServerButton.tsx
index b981b68d0ad..989be3bc8da 100644
--- a/studio/components/interfaces/Settings/General/RestartServerButton.tsx
+++ b/studio/components/interfaces/Settings/General/Infrastructure/RestartServerButton.tsx
@@ -1,9 +1,11 @@
import { FC, useState } from 'react'
import { useRouter } from 'next/router'
import { observer } from 'mobx-react-lite'
+import * as Tooltip from '@radix-ui/react-tooltip'
import { Button, IconRefreshCcw } from '@supabase/ui'
+import { PermissionAction } from '@supabase/shared-types/out/constants'
-import { useStore } from 'hooks'
+import { useStore, checkPermissions } from 'hooks'
import { post } from 'lib/common/fetch'
import { API_URL } from 'lib/constants'
import ConfirmModal from 'components/ui/Dialogs/ConfirmDialog'
@@ -22,6 +24,8 @@ const RestartServerButton: FC = observer(({ projectRef, projectId }) => {
const openModal = () => setIsModalOpen(true)
const closeModal = () => setIsModalOpen(false)
+ const canReboot = checkPermissions(PermissionAction.INFRA_EXECUTE, 'reboot')
+
const requestServerRestart = async () => {
setLoading(true)
const res = await post(`${API_URL}/projects/${projectRef}/restart`, {})
@@ -43,6 +47,34 @@ const RestartServerButton: FC = observer(({ projectRef, projectId }) => {
return (
<>
+
+
+ }
+ onClick={openModal}
+ loading={loading}
+ disabled={!canReboot}
+ >
+ Restart server
+
+
+ {!canReboot && (
+
+
+
+
+ You need additional permissions to restart this project
+
+
+
+ )}
+
= observer(({ projectRef, projectId }) => {
onSelectCancel={closeModal}
onSelectConfirm={requestServerRestart}
/>
- } onClick={openModal} loading={loading}>
- Restart server
-
>
)
})
diff --git a/studio/components/interfaces/Settings/General/index.ts b/studio/components/interfaces/Settings/General/index.ts
index ad686684336..ab4d1031c5e 100644
--- a/studio/components/interfaces/Settings/General/index.ts
+++ b/studio/components/interfaces/Settings/General/index.ts
@@ -1,6 +1,5 @@
-import PauseProjectButton from './PauseProjectButton'
-import RestartServerButton from './RestartServerButton'
+import General from './General'
+import Infrastructure from './Infrastructure/Infrastructure'
+import DeleteProjectPanel from './DeleteProjectPanel'
-import DeleteProjectButton from './DeleteProjectButton'
-
-export { PauseProjectButton, RestartServerButton, DeleteProjectButton }
+export { General, Infrastructure, DeleteProjectPanel }
diff --git a/studio/pages/project/[ref]/settings/general.tsx b/studio/pages/project/[ref]/settings/general.tsx
index 48210d03acc..7cced5a8f45 100644
--- a/studio/pages/project/[ref]/settings/general.tsx
+++ b/studio/pages/project/[ref]/settings/general.tsx
@@ -1,163 +1,20 @@
-import { Alert, Input } from '@supabase/ui'
-import { toJS } from 'mobx'
import { observer } from 'mobx-react-lite'
-import { projects } from 'stores/jsonSchema'
-import { AutoField } from 'uniforms-bootstrap4'
-import { PermissionAction } from '@supabase/shared-types/out/constants'
-import { SettingsLayout } from 'components/layouts'
-import SchemaFormPanel from 'components/to-be-cleaned/forms/SchemaFormPanel'
-import Panel from 'components/ui/Panel'
-import { checkPermissions, useStore } from 'hooks'
-import { post } from 'lib/common/fetch'
-import { API_URL } from 'lib/constants'
-import { pluckJsonSchemaFields, pluckObjectFields } from 'lib/helpers'
import { NextPageWithLayout } from 'types'
-
-import {
- DeleteProjectButton,
- PauseProjectButton,
- RestartServerButton,
-} from 'components/interfaces/Settings/General'
-import { useFlag } from 'hooks'
-import { PRICING_TIER_PRODUCT_IDS } from 'lib/constants'
+import { SettingsLayout } from 'components/layouts'
+import { FormsContainer } from 'components/ui/Forms'
+import { General, Infrastructure, DeleteProjectPanel } from 'components/interfaces/Settings/General'
const ProjectSettings: NextPageWithLayout = () => {
return (
-
+
+
+
+
+
)
}
ProjectSettings.getLayout = (page) => {page}
export default observer(ProjectSettings)
-
-const GeneralSettings = observer(() => {
- const { app, ui } = useStore()
- const isProjectPauseEnabled = useFlag('projectPausing')
-
- const project = ui.selectedProject
- const formModel = toJS(project)
- const BASIC_FIELDS = ['name']
-
- // @ts-ignore
- const canReboot = checkPermissions(PermissionAction.TENANT_INFRA_EXECUTE, 'reboot')
- const canUpdateProject = checkPermissions(PermissionAction.SQL_UPDATE, 'postgres.public.projects')
- const isFreeProject = project?.subscription_tier === PRICING_TIER_PRODUCT_IDS.FREE
-
- const handleUpdateProject = async (model: any) => {
- const response = await post(`${API_URL}/projects/${project?.ref}/update`, model)
- if (response.error) {
- ui.setNotification({
- category: 'error',
- message: `Update project failed: ${response.error.message}`,
- })
- } else {
- const updatedProject = response
- app.onProjectUpdated(updatedProject)
- ui.setNotification({
- category: 'success',
- message: 'Successfully saved settings',
- })
- }
- }
-
- return (
-
-
- handleUpdateProject(pluckObjectFields(model, BASIC_FIELDS))}
- >
-
-
-
-
-
-
- Infrastructure
-
- }
- >
-
-
-
-
-
-
-
-
-
-
Restart server
-
-
- Your project will not be available for a few minutes.
-
-
- {project &&
}
-
- {project &&
}
-
-
- {isProjectPauseEnabled && isFreeProject && (
-
-
-
-
Pause project
-
-
- Your project will not be accessible while it is paused.
-
-
-
- {project &&
}
-
-
- )}
-
-
-
- {project !== undefined && (
-
- Danger Zone}>
-
-
-
-
- Make sure you have made a backup if you want to keep your data.
-
-
-
-
-
-
-
- )}
-
- )
-})