mirror of
https://github.com/supabase/supabase.git
synced 2026-10-12 04:45:08 +03:00
Stacked PR 4/5 for page title improvements. Includes account and organization-level title updates plus organization list/selector page titles. _Base: [dnywh/feat/page-titles](https://github.com/supabase/supabase/pull/43538)_ --- ## What kind of change does this PR introduce? - Resolves FE-1960 - Resolves FE-1983 - Resolves DEPR-207 ## What is the current behavior? Page titles between surfaces are inconsistent and vague. Sometimes they say the product name: ``` My Project | My Org | Supabase ``` ...even when on a specific surface like Database > Tables. Other times they show the entity name but skip over the project or org name : ``` Edge Functions | Supabase ``` ## What is the new behavior? Account and organization-level title updates plus organization list/selector page titles, adopting the layout title format introduced in https://github.com/supabase/supabase/pull/43538: ``` users | Table Editor | My Project | My Org | Supabase hello-world | Logs | Edge Functions | My Project | My Org | Supabase Backups | Database | My Project | My Org | Supabase Authentication | My Project | My Org | Supabase ``` That format is: entity, section, surface, project, org, brand ## Additional context Related stacked PRs also based on the the original [dnywh/feat/page-titles](https://github.com/supabase/supabase/pull/43538) branch: - https://github.com/supabase/supabase/pull/43534 - https://github.com/supabase/supabase/pull/43535 - https://github.com/supabase/supabase/pull/43537 --------- Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
91 lines
3.6 KiB
TypeScript
91 lines
3.6 KiB
TypeScript
import PartnerIcon from 'components/ui/PartnerIcon'
|
|
import { PARTNER_TO_NAME } from 'components/ui/PartnerManagedResource'
|
|
import { useAwsRedirectQuery } from 'data/integrations/aws-redirect-query'
|
|
import { useVercelRedirectQuery } from 'data/integrations/vercel-redirect-query'
|
|
import { useCustomContent } from 'hooks/custom-content/useCustomContent'
|
|
import { useSelectedOrganizationQuery } from 'hooks/misc/useSelectedOrganization'
|
|
import { withAuth } from 'hooks/misc/withAuth'
|
|
import { MANAGED_BY } from 'lib/constants/infrastructure'
|
|
import { buildStudioPageTitle } from 'lib/page-title'
|
|
import { ExternalLink } from 'lucide-react'
|
|
import Head from 'next/head'
|
|
import { useRouter } from 'next/router'
|
|
import type { PropsWithChildren } from 'react'
|
|
import { Alert_Shadcn_, AlertTitle_Shadcn_, Button, cn } from 'ui'
|
|
|
|
import { useRegisterOrgMenu } from './OrganizationLayout/useRegisterOrgMenu'
|
|
|
|
interface OrganizationLayoutProps {
|
|
title: string
|
|
}
|
|
|
|
// [Joshen] Just for page title generation for org settings pages
|
|
const settingsPages = ['general', 'security', 'sso', 'apps', 'audit', 'documents']
|
|
|
|
const OrganizationLayoutContent = ({
|
|
children,
|
|
title,
|
|
}: PropsWithChildren<OrganizationLayoutProps>) => {
|
|
const router = useRouter()
|
|
const { data: selectedOrganization } = useSelectedOrganizationQuery()
|
|
const { appTitle } = useCustomContent(['app:title'])
|
|
|
|
// Keep title intent close to each page (getLayout) to avoid route-to-title drift in this layout.
|
|
const isSettingsSurface = settingsPages.some((x) => router.pathname.endsWith(x))
|
|
const pageTitle = buildStudioPageTitle({
|
|
section: title,
|
|
surface: isSettingsSurface ? 'Organization Settings' : undefined,
|
|
org: selectedOrganization?.name,
|
|
brand: appTitle || 'Supabase',
|
|
})
|
|
|
|
const vercelQuery = useVercelRedirectQuery(
|
|
{ installationId: selectedOrganization?.partner_id },
|
|
{ enabled: selectedOrganization?.managed_by === MANAGED_BY.VERCEL_MARKETPLACE }
|
|
)
|
|
|
|
const awsQuery = useAwsRedirectQuery(
|
|
{ organizationSlug: selectedOrganization?.slug },
|
|
{ enabled: selectedOrganization?.managed_by === MANAGED_BY.AWS_MARKETPLACE }
|
|
)
|
|
|
|
// Select the appropriate query based on partner
|
|
const { data, isSuccess } =
|
|
selectedOrganization?.managed_by === MANAGED_BY.AWS_MARKETPLACE ? awsQuery : vercelQuery
|
|
|
|
return (
|
|
<div className={cn('h-full w-full flex flex-col overflow-hidden')}>
|
|
{pageTitle && (
|
|
<Head>
|
|
<title>{pageTitle}</title>
|
|
<meta name="description" content="Supabase Studio" />
|
|
</Head>
|
|
)}
|
|
{selectedOrganization && selectedOrganization?.managed_by !== 'supabase' && (
|
|
<Alert_Shadcn_
|
|
variant="default"
|
|
className="flex items-center gap-4 border-t-0 border-x-0 rounded-none"
|
|
>
|
|
<PartnerIcon organization={selectedOrganization} showTooltip={false} size="medium" />
|
|
<AlertTitle_Shadcn_ className="flex-1">
|
|
This organization is managed by {PARTNER_TO_NAME[selectedOrganization.managed_by]}.
|
|
</AlertTitle_Shadcn_>
|
|
<Button asChild type="default" iconRight={<ExternalLink />} disabled={!isSuccess}>
|
|
<a href={data?.url} target="_blank" rel="noopener noreferrer">
|
|
Manage
|
|
</a>
|
|
</Button>
|
|
</Alert_Shadcn_>
|
|
)}
|
|
<main className="h-full w-full overflow-y-auto flex flex-col">{children}</main>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
const OrganizationLayout = ({ children, title }: PropsWithChildren<OrganizationLayoutProps>) => {
|
|
useRegisterOrgMenu()
|
|
return <OrganizationLayoutContent title={title}>{children}</OrganizationLayoutContent>
|
|
}
|
|
|
|
export default withAuth(OrganizationLayout)
|