diff --git a/studio/components/layouts/AccountLayout/AccountLayout.tsx b/studio/components/layouts/AccountLayout/AccountLayout.tsx index 9b9adc5b42a..7610e3ecd10 100644 --- a/studio/components/layouts/AccountLayout/AccountLayout.tsx +++ b/studio/components/layouts/AccountLayout/AccountLayout.tsx @@ -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) => {
{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) diff --git a/studio/components/layouts/index.ts b/studio/components/layouts/index.ts index b00d71769d9..5a34f422f14 100644 --- a/studio/components/layouts/index.ts +++ b/studio/components/layouts/index.ts @@ -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 diff --git a/studio/pages/account/me.tsx b/studio/pages/account/me.tsx index 335ef316aed..4b2f5d33bed 100644 --- a/studio/pages/account/me.tsx +++ b/studio/pages/account/me.tsx @@ -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 ( - -
- -
-
+
+ +
) } -export default withAuth(User) +User.getLayout = (page) => ( + + {page} + +) + +export default User const ProfileCard = observer(() => { const { ui } = useStore() @@ -50,7 +55,7 @@ const ProfileCard = observer(() => { } return ( -
+
diff --git a/studio/pages/account/tokens.tsx b/studio/pages/account/tokens.tsx index 7784c3010d5..c2d5ac7a681 100644 --- a/studio/pages/account/tokens.tsx +++ b/studio/pages/account/tokens.tsx @@ -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 ( - -
-

Access Tokens

- - -
-
+
+

Access Tokens

+ + +
) } -export default withAuth(UserAccessTokens) +UserAccessTokens.getLayout = (page) => ( + + {page} + +) + +export default UserAccessTokens diff --git a/studio/pages/index.tsx b/studio/pages/index.tsx index 749e495e572..88a174efc0f 100644 --- a/studio/pages/index.tsx +++ b/studio/pages/index.tsx @@ -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(false) const [selectedProjectToDelete, setSelectedProjectToDelete] = useState() - if (!profile) { - return - } 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 - } - } - const onSelectDeleteProject = async (project: Project) => { setSelectedProjectToDelete(project) setIsDeletingProject(false) @@ -80,16 +54,7 @@ const Home: NextPage = () => { } return ( - + <> {app.organizations.isLoading ? (
@@ -132,10 +97,13 @@ const Home: NextPage = () => { onCancel={() => setSelectedProjectToDelete(undefined)} onConfirm={() => onDeleteProject(selectedProjectToDelete)} /> - + ) } -export default withAuth(observer(Home)) + +Home.getLayout = (page) => {page} + +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 ? : } + +const IndexLayout = withAuth( + observer(({ children }) => { + const { ui } = useStore() + const { profile } = ui + + const router = useRouter() + + if (!profile) { + return + } 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 + } + } + + return ( + + {children} + + ) + }) +) diff --git a/studio/pages/org/[slug]/settings.tsx b/studio/pages/org/[slug]/settings.tsx index 0a2b59e45e5..a83fbad4326 100644 --- a/studio/pages/org/[slug]/settings.tsx +++ b/studio/pages/org/[slug]/settings.tsx @@ -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 ( - - - - ) -} -export default withAuth(observer(OrgSettings)) + return ( + + {children} + + ) + }) +) -const PageLayout = observer(() => { +const OrgSettings: NextPageWithLayout = () => { const { ui } = useStore() - const PageState: any = useContext(PageContext) - return ( - - {ui.selectedOrganization && } - - ) -}) + return <>{ui.selectedOrganization && } +} + +OrgSettings.getLayout = (page) => {page} + +export default observer(OrgSettings) const OrganizationSettings = observer(() => { const PageState: any = useContext(PageContext) @@ -217,7 +219,7 @@ const GeneralSettings = observer(() => { } return ( -
+
{ visible={isOpen} onCancel={toggle} header={ -
-
Delete organisation
- Are you sure? +
+
Delete organisation
+ Are you sure?
} size="small" @@ -416,7 +418,7 @@ const TeamSettings = observer(() => { return ( <> -
+
{PageState.isOrgOwner ? ( @@ -435,7 +437,7 @@ const TeamSettings = observer(() => { )}
-
+
@@ -483,7 +485,7 @@ const MembersView = observer(() => {
@@ -607,7 +609,7 @@ const OwnerDropdown = observer(({ members, member }: any) => { setOwnerTransferIsVisble(!ownerTransferIsVisble)}>

Make owner

-

Transfer ownership of "{orgName}"

+

Transfer ownership of "{orgName}"

@@ -639,7 +641,7 @@ const OwnerDropdown = observer(({ members, member }: any) => { text={ By transferring this organization, it will be solely owned by{' '} - {member.profile.username}, they + {member.profile.username}, they will also be able to remove you from the organization as a member }