mirror of
https://github.com/supabase/supabase.git
synced 2026-10-06 09:55:06 +03:00
chore: move AccountLayout to getLayout
This commit is contained in:
1 parent
e2e534eac1
commit
b0d5c849a4
6 files changed
+195
-164
No files matched your search
@@ -3,7 +3,7 @@ import { useRouter } from 'next/router'
|
||||
import { observer } from 'mobx-react-lite'
|
||||
|
||||
import { API_URL, IS_PLATFORM } from 'lib/constants'
|
||||
import { useStore } from 'hooks'
|
||||
import { useStore, withAuth } from 'hooks'
|
||||
import WithSidebar from './WithSidebar'
|
||||
import { auth } from 'lib/gotrue'
|
||||
|
||||
@@ -118,7 +118,7 @@ const AccountLayout = ({ children, title, breadcrumbs }: any) => {
|
||||
<div className="flex h-full">
|
||||
<main
|
||||
style={{ maxHeight: '100vh' }}
|
||||
className="w-full flex flex-col flex-1 overflow-y-auto"
|
||||
className="flex w-full flex-1 flex-col overflow-y-auto"
|
||||
>
|
||||
<WithSidebar title={title} breadcrumbs={breadcrumbs} links={linksWithHeaders}>
|
||||
{children}
|
||||
@@ -129,4 +129,6 @@ const AccountLayout = ({ children, title, breadcrumbs }: any) => {
|
||||
)
|
||||
}
|
||||
|
||||
export default observer(AccountLayout)
|
||||
export default withAuth(observer(AccountLayout))
|
||||
|
||||
export const AccountLayoutWithoutAuth = observer(AccountLayout)
|
||||
@@ -6,12 +6,13 @@ import DatabaseLayout from './DatabaseLayout/DatabaseLayout'
|
||||
import DocsLayout from './DocsLayout/DocsLayout'
|
||||
import SettingsLayout from './SettingsLayout/SettingsLayout'
|
||||
import StorageLayout from './StorageLayout/StorageLayout'
|
||||
|
||||
import AccountLayout from './AccountLayout/AccountLayout'
|
||||
import { AccountLayoutWithoutAuth } from './AccountLayout/AccountLayout'
|
||||
import WizardLayout from './WizardLayout'
|
||||
import VercelIntegrationLayout from './VercelIntegrationLayout'
|
||||
import BillingLayout from './BillingLayout'
|
||||
import LogsExplorerLayout from './LogsExplorerLayout/LogsExplorerLayout'
|
||||
|
||||
export {
|
||||
AuthLayout,
|
||||
DatabaseLayout,
|
||||
@@ -21,10 +22,11 @@ export {
|
||||
SettingsLayout,
|
||||
StorageLayout,
|
||||
AccountLayout,
|
||||
AccountLayoutWithoutAuth,
|
||||
WizardLayout,
|
||||
VercelIntegrationLayout,
|
||||
BillingLayout,
|
||||
LogsExplorerLayout
|
||||
|
||||
LogsExplorerLayout,
|
||||
}
|
||||
|
||||
export default ProjectLayout
|
||||
+22
-17
@@ -2,32 +2,37 @@ import React from 'react'
|
||||
import { observer } from 'mobx-react-lite'
|
||||
import { IconMoon, IconSun, Typography, Input, Listbox } from '@supabase/ui'
|
||||
|
||||
import { useProfile, useStore, withAuth } from 'hooks'
|
||||
import { useProfile, useStore } from 'hooks'
|
||||
import { post } from 'lib/common/fetch'
|
||||
import { API_URL } from 'lib/constants'
|
||||
import { AccountLayout } from 'components/layouts'
|
||||
import Panel from 'components/to-be-cleaned/Panel'
|
||||
import SchemaFormPanel from 'components/to-be-cleaned/forms/SchemaFormPanel'
|
||||
import { NextPageWithLayout } from 'types'
|
||||
|
||||
const User = () => {
|
||||
const User: NextPageWithLayout = () => {
|
||||
return (
|
||||
<AccountLayout
|
||||
title="Supabase"
|
||||
breadcrumbs={[
|
||||
{
|
||||
key: `supabase-settings`,
|
||||
label: 'Preferences',
|
||||
},
|
||||
]}
|
||||
>
|
||||
<div className="my-2">
|
||||
<ProfileCard />
|
||||
</div>
|
||||
</AccountLayout>
|
||||
<div className="my-2">
|
||||
<ProfileCard />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default withAuth(User)
|
||||
User.getLayout = (page) => (
|
||||
<AccountLayout
|
||||
title="Supabase"
|
||||
breadcrumbs={[
|
||||
{
|
||||
key: `supabase-settings`,
|
||||
label: 'Preferences',
|
||||
},
|
||||
]}
|
||||
>
|
||||
{page}
|
||||
</AccountLayout>
|
||||
)
|
||||
|
||||
export default User
|
||||
|
||||
const ProfileCard = observer(() => {
|
||||
const { ui } = useStore()
|
||||
@@ -50,7 +55,7 @@ const ProfileCard = observer(() => {
|
||||
}
|
||||
|
||||
return (
|
||||
<article className="p-4 max-w-4xl">
|
||||
<article className="max-w-4xl p-4">
|
||||
<section>
|
||||
<GithubProfile />
|
||||
</section>
|
||||
|
||||
@@ -1,25 +1,29 @@
|
||||
import { withAuth } from 'hooks'
|
||||
import { AccountLayout } from 'components/layouts'
|
||||
import { AccessTokenList, NewAccessTokenButton } from 'components/interfaces/Account'
|
||||
import { NextPageWithLayout } from 'types'
|
||||
|
||||
const UserAccessTokens = () => {
|
||||
const UserAccessTokens: NextPageWithLayout = () => {
|
||||
return (
|
||||
<AccountLayout
|
||||
title="Supabase"
|
||||
breadcrumbs={[
|
||||
{
|
||||
key: `supabase-account-tokens`,
|
||||
label: 'Access Tokens',
|
||||
},
|
||||
]}
|
||||
>
|
||||
<div className="p-4 pt-0 mt-4 space-y-8">
|
||||
<h2 className="text-xl">Access Tokens</h2>
|
||||
<NewAccessTokenButton />
|
||||
<AccessTokenList />
|
||||
</div>
|
||||
</AccountLayout>
|
||||
<div className="mt-4 space-y-8 p-4 pt-0">
|
||||
<h2 className="text-xl">Access Tokens</h2>
|
||||
<NewAccessTokenButton />
|
||||
<AccessTokenList />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default withAuth(UserAccessTokens)
|
||||
UserAccessTokens.getLayout = (page) => (
|
||||
<AccountLayout
|
||||
title="Supabase"
|
||||
breadcrumbs={[
|
||||
{
|
||||
key: `supabase-account-tokens`,
|
||||
label: 'Access Tokens',
|
||||
},
|
||||
]}
|
||||
>
|
||||
{page}
|
||||
</AccountLayout>
|
||||
)
|
||||
|
||||
export default UserAccessTokens
|
||||
+57
-41
@@ -5,53 +5,27 @@ import { NextRouter, useRouter } from 'next/router'
|
||||
import { isUndefined } from 'lodash'
|
||||
import { Typography } from '@supabase/ui'
|
||||
|
||||
import { Project } from 'types'
|
||||
import { NextPageWithLayout, Project } from 'types'
|
||||
import { useStore, withAuth } from 'hooks'
|
||||
import { auth } from 'lib/gotrue'
|
||||
import { post, delete_ } from 'lib/common/fetch'
|
||||
import { API_URL, IS_PLATFORM, PROJECT_STATUS } from 'lib/constants'
|
||||
|
||||
import Connecting from 'components/ui/Loading'
|
||||
import { AccountLayout } from 'components/layouts'
|
||||
import { AccountLayoutWithoutAuth } from 'components/layouts'
|
||||
import Landing from 'components/interfaces/Home/Landing'
|
||||
import ProjectList from 'components/interfaces/Home/ProjectList'
|
||||
import OrganizationDropdown from 'components/to-be-cleaned/Dropdown/OrganizationDropdown'
|
||||
import TextConfirmModal from 'components/to-be-cleaned/ModalsDeprecated/TextConfirmModal'
|
||||
|
||||
const Home: NextPage = () => {
|
||||
const Home: NextPageWithLayout = () => {
|
||||
const { app, ui } = useStore()
|
||||
const { profile } = ui
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
const [isDeletingProject, setIsDeletingProject] = useState<boolean>(false)
|
||||
const [selectedProjectToDelete, setSelectedProjectToDelete] = useState<Project>()
|
||||
|
||||
if (!profile) {
|
||||
return <UnauthorizedLanding />
|
||||
} else {
|
||||
const isRedirect = isRedirectFromThirdPartyService(router)
|
||||
if (isRedirect) {
|
||||
const queryParams = (router.query as any) || {}
|
||||
const params = new URLSearchParams(queryParams)
|
||||
if (router.query?.next?.includes('https://vercel.com')) {
|
||||
router.push(`/vercel/integrate?${params.toString()}`)
|
||||
} else if (router.query?.next?.includes('new-project')) {
|
||||
router.push('/new/project')
|
||||
} else if (router.query['x-amzn-marketplace-token'] != undefined) {
|
||||
router.push(`/account/associate?${params.toString()}`)
|
||||
} else if (
|
||||
typeof router.query?.next === 'string' &&
|
||||
router.query?.next?.startsWith('project/_/')
|
||||
) {
|
||||
router.push(router.query.next as string)
|
||||
} else {
|
||||
router.push('/')
|
||||
}
|
||||
return <Connecting />
|
||||
}
|
||||
}
|
||||
|
||||
const onSelectDeleteProject = async (project: Project) => {
|
||||
setSelectedProjectToDelete(project)
|
||||
setIsDeletingProject(false)
|
||||
@@ -80,16 +54,7 @@ const Home: NextPage = () => {
|
||||
}
|
||||
|
||||
return (
|
||||
<AccountLayout
|
||||
title="Supabase"
|
||||
// @ts-ignore
|
||||
breadcrumbs={[
|
||||
{
|
||||
key: `supabase-projects`,
|
||||
label: 'Projects',
|
||||
},
|
||||
]}
|
||||
>
|
||||
<>
|
||||
{app.organizations.isLoading ? (
|
||||
<div className="flex h-full items-center justify-center space-x-2">
|
||||
<Connecting />
|
||||
@@ -132,10 +97,13 @@ const Home: NextPage = () => {
|
||||
onCancel={() => setSelectedProjectToDelete(undefined)}
|
||||
onConfirm={() => onDeleteProject(selectedProjectToDelete)}
|
||||
/>
|
||||
</AccountLayout>
|
||||
</>
|
||||
)
|
||||
}
|
||||
export default withAuth(observer(Home))
|
||||
|
||||
Home.getLayout = (page) => <IndexLayout>{page}</IndexLayout>
|
||||
|
||||
export default observer(Home)
|
||||
|
||||
// detect for redirect from 3rd party service like vercel, aws...
|
||||
function isRedirectFromThirdPartyService(router: NextRouter) {
|
||||
@@ -162,3 +130,51 @@ const UnauthorizedLanding = () => {
|
||||
|
||||
return autoLogin ? <Connecting /> : <Landing />
|
||||
}
|
||||
|
||||
const IndexLayout = withAuth(
|
||||
observer(({ children }) => {
|
||||
const { ui } = useStore()
|
||||
const { profile } = ui
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
if (!profile) {
|
||||
return <UnauthorizedLanding />
|
||||
} else {
|
||||
const isRedirect = isRedirectFromThirdPartyService(router)
|
||||
if (isRedirect) {
|
||||
const queryParams = (router.query as any) || {}
|
||||
const params = new URLSearchParams(queryParams)
|
||||
if (router.query?.next?.includes('https://vercel.com')) {
|
||||
router.push(`/vercel/integrate?${params.toString()}`)
|
||||
} else if (router.query?.next?.includes('new-project')) {
|
||||
router.push('/new/project')
|
||||
} else if (router.query['x-amzn-marketplace-token'] != undefined) {
|
||||
router.push(`/account/associate?${params.toString()}`)
|
||||
} else if (
|
||||
typeof router.query?.next === 'string' &&
|
||||
router.query?.next?.startsWith('project/_/')
|
||||
) {
|
||||
router.push(router.query.next as string)
|
||||
} else {
|
||||
router.push('/')
|
||||
}
|
||||
return <Connecting />
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<AccountLayoutWithoutAuth
|
||||
title="Supabase"
|
||||
breadcrumbs={[
|
||||
{
|
||||
key: `supabase-projects`,
|
||||
label: 'Projects',
|
||||
},
|
||||
]}
|
||||
>
|
||||
{children}
|
||||
</AccountLayoutWithoutAuth>
|
||||
)
|
||||
})
|
||||
)
|
||||
@@ -23,7 +23,7 @@ import {
|
||||
import { API_URL } from 'lib/constants'
|
||||
import { useOrganizationDetail, useStore, withAuth } from 'hooks'
|
||||
import { post, delete_, patch } from 'lib/common/fetch'
|
||||
import { AccountLayout } from 'components/layouts'
|
||||
import { AccountLayoutWithoutAuth } from 'components/layouts'
|
||||
import { BillingSettings, InvoicesSettings } from 'components/interfaces/Organization'
|
||||
|
||||
import Table from 'components/to-be-cleaned/Table'
|
||||
@@ -32,91 +32,93 @@ import { confirmAlert } from 'components/to-be-cleaned/ModalsDeprecated/ConfirmM
|
||||
import InviteMemberModal from 'components/to-be-cleaned/ModalsDeprecated/InviteMemberModal'
|
||||
import TextConfirmModal from 'components/to-be-cleaned/ModalsDeprecated/TextConfirmModal'
|
||||
import SchemaFormPanel from 'components/to-be-cleaned/forms/SchemaFormPanel'
|
||||
import { Project } from 'types'
|
||||
import { NextPageWithLayout, Project } from 'types'
|
||||
|
||||
// [Joshen] Low prio refactor: Bring out general and team settings into their own components too
|
||||
|
||||
const PageContext = createContext(null)
|
||||
|
||||
const OrgSettings = () => {
|
||||
const { app, ui } = useStore()
|
||||
const router = useRouter()
|
||||
const PageState: any = useLocalObservable(() => ({
|
||||
user: {} as any,
|
||||
organization: {},
|
||||
projects: [],
|
||||
members: [],
|
||||
products: [],
|
||||
membersFilterString: '',
|
||||
get isOrgOwner() {
|
||||
return (
|
||||
this.members.find((x: any) => x.profile.id === this.user?.id && x.is_owner) != undefined
|
||||
)
|
||||
},
|
||||
get filteredMembers() {
|
||||
const temp = this.members.filter((x: any) => {
|
||||
let profile = x.profile
|
||||
const OrgSettingsLayout = withAuth(
|
||||
observer(({ children }) => {
|
||||
const { app, ui } = useStore()
|
||||
const router = useRouter()
|
||||
const PageState: any = useLocalObservable(() => ({
|
||||
user: {} as any,
|
||||
organization: {},
|
||||
projects: [],
|
||||
members: [],
|
||||
products: [],
|
||||
membersFilterString: '',
|
||||
get isOrgOwner() {
|
||||
return (
|
||||
profile.username.includes(this.membersFilterString) ||
|
||||
profile.primary_email.includes(this.membersFilterString)
|
||||
this.members.find((x: any) => x.profile.id === this.user?.id && x.is_owner) != undefined
|
||||
)
|
||||
})
|
||||
return temp.sort((a: any, b: any) => a.profile.username.localeCompare(b.profile.username))
|
||||
},
|
||||
initData(organization: any, user: any, projects: any) {
|
||||
this.organization = organization
|
||||
this.user = user
|
||||
this.projects = projects
|
||||
},
|
||||
onOrgUpdated(updatedOrg: any) {
|
||||
app.onOrgUpdated(updatedOrg)
|
||||
},
|
||||
onOrgDeleted() {
|
||||
app.onOrgDeleted(this.organization)
|
||||
},
|
||||
}))
|
||||
},
|
||||
get filteredMembers() {
|
||||
const temp = this.members.filter((x: any) => {
|
||||
let profile = x.profile
|
||||
return (
|
||||
profile.username.includes(this.membersFilterString) ||
|
||||
profile.primary_email.includes(this.membersFilterString)
|
||||
)
|
||||
})
|
||||
return temp.sort((a: any, b: any) => a.profile.username.localeCompare(b.profile.username))
|
||||
},
|
||||
initData(organization: any, user: any, projects: any) {
|
||||
this.organization = organization
|
||||
this.user = user
|
||||
this.projects = projects
|
||||
},
|
||||
onOrgUpdated(updatedOrg: any) {
|
||||
app.onOrgUpdated(updatedOrg)
|
||||
},
|
||||
onOrgDeleted() {
|
||||
app.onOrgDeleted(this.organization)
|
||||
},
|
||||
}))
|
||||
|
||||
useEffect(() => {
|
||||
// User added a new payment method
|
||||
if (router.query.setup_intent && router.query.redirect_status) {
|
||||
ui.setNotification({ category: 'success', message: 'Successfully added new payment method' })
|
||||
}
|
||||
}, [])
|
||||
useEffect(() => {
|
||||
// User added a new payment method
|
||||
if (router.query.setup_intent && router.query.redirect_status) {
|
||||
ui.setNotification({
|
||||
category: 'success',
|
||||
message: 'Successfully added new payment method',
|
||||
})
|
||||
}
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
const organization = ui.selectedOrganization
|
||||
const user = ui.profile
|
||||
const projects = app.projects.list((x: Project) => x.organization_id == organization?.id)
|
||||
PageState.initData(organization, user, projects)
|
||||
}, [ui.selectedOrganization, ui.profile])
|
||||
useEffect(() => {
|
||||
const organization = ui.selectedOrganization
|
||||
const user = ui.profile
|
||||
const projects = app.projects.list((x: Project) => x.organization_id == organization?.id)
|
||||
PageState.initData(organization, user, projects)
|
||||
}, [ui.selectedOrganization, ui.profile])
|
||||
|
||||
return (
|
||||
<PageContext.Provider value={PageState}>
|
||||
<PageLayout />
|
||||
</PageContext.Provider>
|
||||
)
|
||||
}
|
||||
export default withAuth(observer(OrgSettings))
|
||||
return (
|
||||
<AccountLayoutWithoutAuth
|
||||
title={PageState.organization?.name || 'Supabase'}
|
||||
breadcrumbs={[
|
||||
{
|
||||
key: `org-settings`,
|
||||
label: 'Settings',
|
||||
},
|
||||
]}
|
||||
>
|
||||
<PageContext.Provider value={PageState}>{children}</PageContext.Provider>
|
||||
</AccountLayoutWithoutAuth>
|
||||
)
|
||||
})
|
||||
)
|
||||
|
||||
const PageLayout = observer(() => {
|
||||
const OrgSettings: NextPageWithLayout = () => {
|
||||
const { ui } = useStore()
|
||||
const PageState: any = useContext(PageContext)
|
||||
|
||||
return (
|
||||
<AccountLayout
|
||||
title={PageState.organization?.name || 'Supabase'}
|
||||
// @ts-ignore
|
||||
breadcrumbs={[
|
||||
{
|
||||
key: `org-settings`,
|
||||
label: 'Settings',
|
||||
},
|
||||
]}
|
||||
>
|
||||
{ui.selectedOrganization && <OrganizationSettings />}
|
||||
</AccountLayout>
|
||||
)
|
||||
})
|
||||
return <>{ui.selectedOrganization && <OrganizationSettings />}</>
|
||||
}
|
||||
|
||||
OrgSettings.getLayout = (page) => <OrgSettingsLayout>{page}</OrgSettingsLayout>
|
||||
|
||||
export default observer(OrgSettings)
|
||||
|
||||
const OrganizationSettings = observer(() => {
|
||||
const PageState: any = useContext(PageContext)
|
||||
@@ -217,7 +219,7 @@ const GeneralSettings = observer(() => {
|
||||
}
|
||||
|
||||
return (
|
||||
<article className="my-4 container max-w-4xl space-y-8">
|
||||
<article className="container my-4 max-w-4xl space-y-8">
|
||||
<SchemaFormPanel
|
||||
title="General"
|
||||
schema={pluckJsonSchemaFields(organizations, BASIC_FIELDS)}
|
||||
@@ -300,9 +302,9 @@ const OrgDeleteModal = observer(() => {
|
||||
visible={isOpen}
|
||||
onCancel={toggle}
|
||||
header={
|
||||
<div className="flex gap-2 items-baseline">
|
||||
<h5 className="text-sm text-scale-1200">Delete organisation</h5>
|
||||
<span className="text-xs text-scale-900">Are you sure?</span>
|
||||
<div className="flex items-baseline gap-2">
|
||||
<h5 className="text-scale-1200 text-sm">Delete organisation</h5>
|
||||
<span className="text-scale-900 text-xs">Are you sure?</span>
|
||||
</div>
|
||||
}
|
||||
size="small"
|
||||
@@ -416,7 +418,7 @@ const TeamSettings = observer(() => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="my-4 container max-w-4xl space-y-8">
|
||||
<div className="container my-4 max-w-4xl space-y-8">
|
||||
<div className="flex justify-between">
|
||||
<MembersFilterInput />
|
||||
{PageState.isOrgOwner ? (
|
||||
@@ -435,7 +437,7 @@ const TeamSettings = observer(() => {
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="my-4 container max-w-4xl space-y-8">
|
||||
<div className="container my-4 max-w-4xl space-y-8">
|
||||
<MembersView />
|
||||
</div>
|
||||
</>
|
||||
@@ -483,7 +485,7 @@ const MembersView = observer(() => {
|
||||
<img
|
||||
src={`https://github.com/${x.profile.username}.png?size=80`}
|
||||
width="40"
|
||||
className="rounded-full border border-border-secondary-light dark:border-border-secondary-dark"
|
||||
className="border-border-secondary-light dark:border-border-secondary-dark rounded-full border"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
@@ -607,7 +609,7 @@ const OwnerDropdown = observer(({ members, member }: any) => {
|
||||
<Dropdown.Item onClick={() => setOwnerTransferIsVisble(!ownerTransferIsVisble)}>
|
||||
<div className="flex flex-col">
|
||||
<p>Make owner</p>
|
||||
<p className="opacity-50 block">Transfer ownership of "{orgName}"</p>
|
||||
<p className="block opacity-50">Transfer ownership of "{orgName}"</p>
|
||||
</div>
|
||||
</Dropdown.Item>
|
||||
<Dropdown.Seperator />
|
||||
@@ -639,7 +641,7 @@ const OwnerDropdown = observer(({ members, member }: any) => {
|
||||
text={
|
||||
<span>
|
||||
By transferring this organization, it will be solely owned by{' '}
|
||||
<span className="dark:text-white font-medium">{member.profile.username}</span>, they
|
||||
<span className="font-medium dark:text-white">{member.profile.username}</span>, they
|
||||
will also be able to remove you from the organization as a member
|
||||
</span>
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user