From 8e3419834a3753d7d22dcb60af42df6e0716c42e Mon Sep 17 00:00:00 2001 From: Joshen Lim Date: Thu, 2 Oct 2025 03:16:35 +0800 Subject: [PATCH] Chore/add flag for html title (#39173) * Add flag for custom html title * nit --- .../layouts/APIAuthorizationLayout.tsx | 5 +++- .../layouts/AccountLayout/AccountLayout.tsx | 6 ++++- .../layouts/LinkAwsMarketplaceLayout.tsx | 5 +++- .../layouts/ProjectLayout/ProjectLayout.tsx | 14 +++++++---- .../custom-content/CustomContent.types.ts | 2 ++ .../hooks/custom-content/custom-content.json | 2 ++ .../custom-content/custom-content.sample.json | 2 ++ .../custom-content/custom-content.schema.json | 6 +++++ apps/studio/pages/_app.tsx | 4 +++- apps/studio/pages/claim-project.tsx | 23 ++++++++++++++----- 10 files changed, 54 insertions(+), 15 deletions(-) diff --git a/apps/studio/components/layouts/APIAuthorizationLayout.tsx b/apps/studio/components/layouts/APIAuthorizationLayout.tsx index bebbb882323..4dada71df95 100644 --- a/apps/studio/components/layouts/APIAuthorizationLayout.tsx +++ b/apps/studio/components/layouts/APIAuthorizationLayout.tsx @@ -1,3 +1,4 @@ +import { useCustomContent } from 'hooks/custom-content/useCustomContent' import { BASE_PATH } from 'lib/constants' import { useTheme } from 'next-themes' import Head from 'next/head' @@ -9,10 +10,12 @@ export interface APIAuthorizationLayoutProps {} const APIAuthorizationLayout = ({ children }: PropsWithChildren) => { const { resolvedTheme } = useTheme() + const { appTitle } = useCustomContent(['app:title']) + return ( <> - Authorize API access | Supabase + Authorize API access | {appTitle || 'Supabase'}
diff --git a/apps/studio/components/layouts/AccountLayout/AccountLayout.tsx b/apps/studio/components/layouts/AccountLayout/AccountLayout.tsx index cf709526141..679f916b09f 100644 --- a/apps/studio/components/layouts/AccountLayout/AccountLayout.tsx +++ b/apps/studio/components/layouts/AccountLayout/AccountLayout.tsx @@ -3,6 +3,7 @@ import { useRouter } from 'next/router' import { PropsWithChildren, useEffect } from 'react' import { LOCAL_STORAGE_KEYS } from 'common' +import { useCustomContent } from 'hooks/custom-content/useCustomContent' import { useLocalStorageQuery } from 'hooks/misc/useLocalStorage' import { withAuth } from 'hooks/misc/withAuth' import { IS_PLATFORM } from 'lib/constants' @@ -18,6 +19,9 @@ const AccountLayout = ({ children, title }: PropsWithChildren - {title ? `${title} | Supabase` : 'Supabase'} + {title ? `${title} | ${titleSuffix}` : titleSuffix}
diff --git a/apps/studio/components/layouts/LinkAwsMarketplaceLayout.tsx b/apps/studio/components/layouts/LinkAwsMarketplaceLayout.tsx index 8baff253240..1f14f57b65d 100644 --- a/apps/studio/components/layouts/LinkAwsMarketplaceLayout.tsx +++ b/apps/studio/components/layouts/LinkAwsMarketplaceLayout.tsx @@ -1,3 +1,4 @@ +import { useCustomContent } from 'hooks/custom-content/useCustomContent' import { BASE_PATH } from 'lib/constants' import { useTheme } from 'next-themes' import Head from 'next/head' @@ -12,10 +13,12 @@ const LinkAwsMarketplaceLayout = ({ children, }: PropsWithChildren) => { const { resolvedTheme } = useTheme() + const { appTitle } = useCustomContent(['app:title']) + return ( <> - AWS Marketplace Setup | Supabase + AWS Marketplace Setup | {appTitle || 'Supabase'}
diff --git a/apps/studio/components/layouts/ProjectLayout/ProjectLayout.tsx b/apps/studio/components/layouts/ProjectLayout/ProjectLayout.tsx index a9f7e2403cc..02654ef391b 100644 --- a/apps/studio/components/layouts/ProjectLayout/ProjectLayout.tsx +++ b/apps/studio/components/layouts/ProjectLayout/ProjectLayout.tsx @@ -9,6 +9,7 @@ import ProjectAPIDocs from 'components/interfaces/ProjectAPIDocs/ProjectAPIDocs' import { AIAssistant } from 'components/ui/AIAssistantPanel/AIAssistant' import { Loading } from 'components/ui/Loading' import { ResourceExhaustionWarningBanner } from 'components/ui/ResourceExhaustionWarningBanner/ResourceExhaustionWarningBanner' +import { useCustomContent } from 'hooks/custom-content/useCustomContent' import { useSelectedOrganizationQuery } from 'hooks/misc/useSelectedOrganization' import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject' import { withAuth } from 'hooks/misc/withAuth' @@ -94,6 +95,9 @@ const ProjectLayout = forwardRef aiSnap.toggleAssistant(), 'i', [aiSnap]) const editor = useEditorType() @@ -124,14 +128,14 @@ const ProjectLayout = forwardRef {title - ? `${title} | Supabase` + ? `${title} | ${titleSuffix}` : selectedTable - ? `${selectedTable} | ${projectName} | ${organizationName} | Supabase` + ? `${selectedTable} | ${projectName} | ${organizationName} | ${titleSuffix}` : projectName - ? `${projectName} | ${organizationName} | Supabase` + ? `${projectName} | ${organizationName} | ${titleSuffix}` : organizationName - ? `${organizationName} | Supabase` - : 'Supabase'} + ? `${organizationName} | ${titleSuffix}` + : titleSuffix} diff --git a/apps/studio/hooks/custom-content/CustomContent.types.ts b/apps/studio/hooks/custom-content/CustomContent.types.ts index a84484def9c..4aa8b0216c8 100644 --- a/apps/studio/hooks/custom-content/CustomContent.types.ts +++ b/apps/studio/hooks/custom-content/CustomContent.types.ts @@ -1,6 +1,8 @@ import type { CloudProvider } from 'shared-data' export type CustomContentTypes = { + appTitle: string + dashboardAuthCustomProvider: string organizationLegalDocuments: { diff --git a/apps/studio/hooks/custom-content/custom-content.json b/apps/studio/hooks/custom-content/custom-content.json index 2702c8c2728..10dfa88265f 100644 --- a/apps/studio/hooks/custom-content/custom-content.json +++ b/apps/studio/hooks/custom-content/custom-content.json @@ -1,6 +1,8 @@ { "$schema": "./custom-content.schema.json", + "app:title": null, + "dashboard_auth:custom_provider": null, "organization:legal_documents": null, diff --git a/apps/studio/hooks/custom-content/custom-content.sample.json b/apps/studio/hooks/custom-content/custom-content.sample.json index b7adc83af68..943d5451273 100644 --- a/apps/studio/hooks/custom-content/custom-content.sample.json +++ b/apps/studio/hooks/custom-content/custom-content.sample.json @@ -1,6 +1,8 @@ { "$schema": "./custom-content.schema.json", + "app:title": "Test Title", + "dashboard_auth:custom_provider": "Nimbus", "organization:legal_documents": [ diff --git a/apps/studio/hooks/custom-content/custom-content.schema.json b/apps/studio/hooks/custom-content/custom-content.schema.json index af9bd62d272..208c77c01fd 100644 --- a/apps/studio/hooks/custom-content/custom-content.schema.json +++ b/apps/studio/hooks/custom-content/custom-content.schema.json @@ -6,6 +6,11 @@ "type": "string" }, + "app:title": { + "type": ["string", "null"], + "description": "Render a custom HTML title for the site" + }, + "dashboard_auth:custom_provider": { "type": ["string", "null"], "description": "Show a custom provider on the sign in page (Continue with X)" @@ -85,6 +90,7 @@ } }, "required": [ + "app:title", "organization:legal_documents", "project_homepage:client_libraries", "project_homepage:example_projects", diff --git a/apps/studio/pages/_app.tsx b/apps/studio/pages/_app.tsx index a4034e0b3ef..7eea0ec1d04 100644 --- a/apps/studio/pages/_app.tsx +++ b/apps/studio/pages/_app.tsx @@ -50,6 +50,7 @@ import { MonacoThemeProvider } from 'components/interfaces/App/MonacoThemeProvid import { GlobalErrorBoundaryState } from 'components/ui/GlobalErrorBoundaryState' import { useRootQueryClient } from 'data/query-client' import { customFont, sourceCodePro } from 'fonts' +import { useCustomContent } from 'hooks/custom-content/useCustomContent' import { AuthProvider } from 'lib/auth' import { API_URL, BASE_PATH, IS_PLATFORM, useDefaultProvider } from 'lib/constants' import { ProfileProvider } from 'lib/profile' @@ -84,6 +85,7 @@ loader.config({ function CustomApp({ Component, pageProps }: AppPropsWithLayout) { const queryClient = useRootQueryClient() + const { appTitle } = useCustomContent(['app:title']) const getLayout = Component.getLayout ?? ((page) => page) @@ -127,7 +129,7 @@ function CustomApp({ Component, pageProps }: AppPropsWithLayout) { > - Supabase + {appTitle ?? 'Supabase'} {/* [Alaister]: This has to be an inline style tag here and not a separate component due to next/font */} diff --git a/apps/studio/pages/claim-project.tsx b/apps/studio/pages/claim-project.tsx index f534495011e..a109a561195 100644 --- a/apps/studio/pages/claim-project.tsx +++ b/apps/studio/pages/claim-project.tsx @@ -1,5 +1,5 @@ import Head from 'next/head' -import { useMemo, useState } from 'react' +import { PropsWithChildren, useMemo, useState } from 'react' import { useParams } from 'common' import { ProjectClaimBenefits } from 'components/interfaces/Organization/ProjectClaim/benefits' @@ -10,10 +10,24 @@ import ShimmeringLoader from 'components/ui/ShimmeringLoader' import { useApiAuthorizationQuery } from 'data/api-authorization/api-authorization-query' import { useOrganizationProjectClaimQuery } from 'data/organizations/organization-project-claim-query' import { useOrganizationsQuery } from 'data/organizations/organizations-query' +import { useCustomContent } from 'hooks/custom-content/useCustomContent' import { withAuth } from 'hooks/misc/withAuth' import type { NextPageWithLayout } from 'types' import { Admonition } from 'ui-patterns' +const ClaimProjectPageLayout = ({ children }: PropsWithChildren) => { + const { appTitle } = useCustomContent(['app:title']) + + return ( + <> + + Claim project | {appTitle || 'Supabase'} + + {children} + + ) +} + const ClaimProjectPage: NextPageWithLayout = () => { const { auth_id, token: claimToken } = useParams() const [selectedOrgSlug, setSelectedOrgSlug] = useState() @@ -111,12 +125,9 @@ const ClaimProjectPage: NextPageWithLayout = () => { } ClaimProjectPage.getLayout = (page) => ( - <> - - Claim project | Supabase - +
{page}
- +
) export default withAuth(ClaimProjectPage)