From be45baf6c4ca49d8c6da95160fd0d0b8ea9a94bc Mon Sep 17 00:00:00 2001 From: Alaister Young Date: Mon, 18 Aug 2025 15:59:24 +0800 Subject: [PATCH] feat: disable project homepage features (#37990) * feat: disable logs features * feat: disable project homepage features * Minor nit fixes * Fix TS * Rename profile:update to profile:show_information --------- Co-authored-by: Joshen Lim --- .../Home/NewProjectPanel/APIKeys.tsx | 69 +++++++----- .../Home/NewProjectPanel/GetStartedHero.tsx | 4 +- .../Home/NewProjectPanel/NewProjectPanel.tsx | 8 +- .../components/interfaces/Home/index.ts | 1 - .../layouts/ProjectLayout/BuildingState.tsx | 39 +++++-- apps/studio/pages/account/me.tsx | 6 +- apps/studio/pages/new/[slug].tsx | 9 +- apps/studio/pages/project/[ref]/index.tsx | 105 +++++++++++------- .../enabled-features/enabled-features.json | 11 +- .../enabled-features.schema.json | 44 +++++++- 10 files changed, 198 insertions(+), 98 deletions(-) diff --git a/apps/studio/components/interfaces/Home/NewProjectPanel/APIKeys.tsx b/apps/studio/components/interfaces/Home/NewProjectPanel/APIKeys.tsx index 05872a5834f..d2779272463 100644 --- a/apps/studio/components/interfaces/Home/NewProjectPanel/APIKeys.tsx +++ b/apps/studio/components/interfaces/Home/NewProjectPanel/APIKeys.tsx @@ -10,6 +10,7 @@ import { getKeys, useAPIKeysQuery } from 'data/api-keys/api-keys-query' import { useJwtSecretUpdatingStatusQuery } from 'data/config/jwt-secret-updating-status-query' import { useProjectSettingsV2Query } from 'data/config/project-settings-v2-query' import { useAsyncCheckProjectPermissions } from 'hooks/misc/useCheckPermissions' +import { useIsFeatureEnabled } from 'hooks/misc/useIsFeatureEnabled' import { Input, SimpleCodeBlock } from 'ui' const generateInitSnippet = (endpoint: string) => ({ @@ -29,12 +30,20 @@ Future main() async { }`, }) -const APIKeys = () => { +export const APIKeys = () => { const { ref: projectRef } = useParams() + const { + projectConnectionJavascriptExample: javascriptExampleEnabled, + projectConnectionDartExample: dartExampleEnabled, + } = useIsFeatureEnabled([ + 'project_connection:javascript_example', + 'project_connection:dart_example', + ]) + const availableLanguages = [ - { name: 'Javascript', key: 'js' }, - { name: 'Dart', key: 'dart' }, + ...(javascriptExampleEnabled ? [{ name: 'Javascript', key: 'js' }] : []), + ...(dartExampleEnabled ? [{ name: 'Dart', key: 'dart' }] : []), ] const [selectedLanguage, setSelectedLanguage] = useState(availableLanguages[0]) @@ -78,7 +87,9 @@ const APIKeys = () => { const apiUrl = `${protocol}://${endpoint ?? '-'}` const clientInitSnippet: any = generateInitSnippet(apiUrl) - const selectedLanguageSnippet = clientInitSnippet[selectedLanguage.key] ?? 'No snippet available' + const selectedLanguageSnippet = !!selectedLanguage + ? clientInitSnippet[selectedLanguage.key] + : 'No snippet available' return ( { } /> -
-
- {availableLanguages.map((language) => { - const isSelected = selectedLanguage.key === language.key - return ( -
setSelectedLanguage(language)} - > - {language.name} -
- ) - })} + {availableLanguages.length > 0 && ( +
+
+ {availableLanguages.map((language) => { + const isSelected = selectedLanguage.key === language.key + return ( +
setSelectedLanguage(language)} + > + {language.name} +
+ ) + })} +
+
+ + {selectedLanguageSnippet} + +
-
- - {selectedLanguageSnippet} - -
-
+ )} )} ) } - -export default APIKeys diff --git a/apps/studio/components/interfaces/Home/NewProjectPanel/GetStartedHero.tsx b/apps/studio/components/interfaces/Home/NewProjectPanel/GetStartedHero.tsx index c4f503a1932..159b50a8f78 100644 --- a/apps/studio/components/interfaces/Home/NewProjectPanel/GetStartedHero.tsx +++ b/apps/studio/components/interfaces/Home/NewProjectPanel/GetStartedHero.tsx @@ -31,7 +31,7 @@ const Row = ({
) -const GetStartedHero = () => { +export const GetStartedHero = () => { return (
{
) } - -export default GetStartedHero diff --git a/apps/studio/components/interfaces/Home/NewProjectPanel/NewProjectPanel.tsx b/apps/studio/components/interfaces/Home/NewProjectPanel/NewProjectPanel.tsx index f500af68809..9dff47b68a1 100644 --- a/apps/studio/components/interfaces/Home/NewProjectPanel/NewProjectPanel.tsx +++ b/apps/studio/components/interfaces/Home/NewProjectPanel/NewProjectPanel.tsx @@ -7,10 +7,10 @@ import { EditorIndexPageLink } from 'data/prefetchers/project.$ref.editor' import { useIsFeatureEnabled } from 'hooks/misc/useIsFeatureEnabled' import { Auth, EdgeFunctions, Realtime, SqlEditor, Storage, TableEditor } from 'icons' import { Button } from 'ui' -import APIKeys from './APIKeys' -import GetStartedHero from './GetStartedHero' +import { APIKeys } from './APIKeys' +import { GetStartedHero } from './GetStartedHero' -const NewProjectPanel = () => { +export const NewProjectPanel = () => { const { ref } = useParams() const { @@ -261,5 +261,3 @@ const NewProjectPanel = () => {
) } - -export default NewProjectPanel diff --git a/apps/studio/components/interfaces/Home/index.ts b/apps/studio/components/interfaces/Home/index.ts index 003fa0a4159..5780ca6d194 100644 --- a/apps/studio/components/interfaces/Home/index.ts +++ b/apps/studio/components/interfaces/Home/index.ts @@ -1,3 +1,2 @@ export { default as ClientLibrary } from './ClientLibrary' export { default as ExampleProject } from './ExampleProject' -export { default as NewProjectPanel } from './NewProjectPanel/NewProjectPanel' diff --git a/apps/studio/components/layouts/ProjectLayout/BuildingState.tsx b/apps/studio/components/layouts/ProjectLayout/BuildingState.tsx index f8ec5d42971..e52bae2142d 100644 --- a/apps/studio/components/layouts/ProjectLayout/BuildingState.tsx +++ b/apps/studio/components/layouts/ProjectLayout/BuildingState.tsx @@ -1,6 +1,7 @@ import { useQueryClient } from '@tanstack/react-query' import { ArrowRight, Loader2 } from 'lucide-react' import Link from 'next/link' +import { useMemo } from 'react' import { useParams } from 'common' import ClientLibrary from 'components/interfaces/Home/ClientLibrary' @@ -10,6 +11,7 @@ import { DisplayApiSettings, DisplayConfigSettings } from 'components/ui/Project import { invalidateProjectDetailsQuery } from 'data/projects/project-detail-query' import { useProjectStatusQuery } from 'data/projects/project-status-query' import { invalidateProjectsQuery } from 'data/projects/projects-query' +import { useIsFeatureEnabled } from 'hooks/misc/useIsFeatureEnabled' import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject' import { PROJECT_STATUS } from 'lib/constants' import { Badge, Button } from 'ui' @@ -19,6 +21,21 @@ const BuildingState = () => { const { data: project } = useSelectedProjectQuery() const queryClient = useQueryClient() + const { + projectHomepageShowAllClientLibraries: showAllClientLibraries, + projectHomepageShowExamples: showExamples, + } = useIsFeatureEnabled([ + 'project_homepage:show_all_client_libraries', + 'project_homepage:show_examples', + ]) + + const clientLibraries = useMemo(() => { + if (showAllClientLibraries) { + return CLIENT_LIBRARIES + } + return CLIENT_LIBRARIES.filter((library) => library.language === 'JavaScript') + }, [showAllClientLibraries]) + useProjectStatusQuery( { projectRef: ref }, { @@ -125,21 +142,23 @@ const BuildingState = () => {

Client libraries

- {CLIENT_LIBRARIES.map((library) => ( + {clientLibraries.map((library) => ( ))}
-
-
-
Example projects
+ {showExamples && ( +
+
+
Example projects
+
+
+ {EXAMPLE_PROJECTS.map((project) => ( + + ))} +
-
- {EXAMPLE_PROJECTS.map((project) => ( - - ))} -
-
+ )}
)} diff --git a/apps/studio/pages/account/me.tsx b/apps/studio/pages/account/me.tsx index d842fba7788..28eee68c799 100644 --- a/apps/studio/pages/account/me.tsx +++ b/apps/studio/pages/account/me.tsx @@ -1,7 +1,7 @@ +import { AccountConnections } from 'components/interfaces/Account/Preferences/AccountConnections' import { AccountDeletion } from 'components/interfaces/Account/Preferences/AccountDeletion' import { AccountIdentities } from 'components/interfaces/Account/Preferences/AccountIdentities' import { AnalyticsSettings } from 'components/interfaces/Account/Preferences/AnalyticsSettings' -import { AccountConnections } from 'components/interfaces/Account/Preferences/AccountConnections' import { ProfileInformation } from 'components/interfaces/Account/Preferences/ProfileInformation' import { ThemeSettings } from 'components/interfaces/Account/Preferences/ThemeSettings' import AccountLayout from 'components/layouts/AccountLayout/AccountLayout' @@ -35,7 +35,7 @@ User.getLayout = (page) => ( export default User const ProfileCard = () => { - const profileUpdateEnabled = useIsFeatureEnabled('profile:update') + const profileShowInformation = useIsFeatureEnabled('profile:show_information') const { error, isLoading, isError, isSuccess } = useProfile() return ( @@ -56,7 +56,7 @@ const ProfileCard = () => { )} {isSuccess && ( <> - {profileUpdateEnabled && isSuccess ? : null} + {profileShowInformation && isSuccess ? : null} )} diff --git a/apps/studio/pages/new/[slug].tsx b/apps/studio/pages/new/[slug].tsx index 311c60f67c9..4af192cd973 100644 --- a/apps/studio/pages/new/[slug].tsx +++ b/apps/studio/pages/new/[slug].tsx @@ -47,6 +47,7 @@ import { import { useProjectsQuery } from 'data/projects/projects-query' import { useSendEventMutation } from 'data/telemetry/send-event-mutation' import { useCheckPermissions } from 'hooks/misc/useCheckPermissions' +import { useIsFeatureEnabled } from 'hooks/misc/useIsFeatureEnabled' import { useLocalStorageQuery } from 'hooks/misc/useLocalStorage' import { useSelectedOrganizationQuery } from 'hooks/misc/useSelectedOrganization' import { withAuth } from 'hooks/misc/withAuth' @@ -136,6 +137,8 @@ const Wizard: NextPageWithLayout = () => { '' ) + const showAdvancedConfig = useIsFeatureEnabled('project_creation:show_advanced_config') + // This is to make the database.new redirect work correctly. The database.new redirect should be set to supabase.com/dashboard/new/last-visited-org if (slug === 'last-visited-org') { if (lastVisitedOrganization) { @@ -303,7 +306,7 @@ const Wizard: NextPageWithLayout = () => { dbRegion, organizationSlug: organization, }, - { enabled: currentOrg != null && !isManagedByVercel } + { enabled: currentOrg !== null && !isManagedByVercel } ) // [kevin] This will eventually all be provided by a new API endpoint to preview and validate project creation, this is just for kaizen now @@ -908,7 +911,9 @@ const Wizard: NextPageWithLayout = () => { )} - {!!availableOrioleVersion && } + {showAdvancedConfig && !!availableOrioleVersion && ( + + )} )} diff --git a/apps/studio/pages/project/[ref]/index.tsx b/apps/studio/pages/project/[ref]/index.tsx index 1ca640ba44b..a61590463f7 100644 --- a/apps/studio/pages/project/[ref]/index.tsx +++ b/apps/studio/pages/project/[ref]/index.tsx @@ -1,11 +1,12 @@ import dayjs from 'dayjs' import Link from 'next/link' -import { useEffect, useRef } from 'react' +import { useEffect, useMemo, useRef } from 'react' import { useParams } from 'common' -import { ClientLibrary, ExampleProject, NewProjectPanel } from 'components/interfaces/Home' +import { ClientLibrary, ExampleProject } from 'components/interfaces/Home' import { AdvisorWidget } from 'components/interfaces/Home/AdvisorWidget' import { CLIENT_LIBRARIES, EXAMPLE_PROJECTS } from 'components/interfaces/Home/Home.constants' +import { NewProjectPanel } from 'components/interfaces/Home/NewProjectPanel/NewProjectPanel' import { ProjectUsageSection } from 'components/interfaces/Home/ProjectUsageSection' import { ServiceStatus } from 'components/interfaces/Home/ServiceStatus' import DefaultLayout from 'components/layouts/DefaultLayout' @@ -18,6 +19,7 @@ import { useBranchesQuery } from 'data/branches/branches-query' import { useEdgeFunctionsQuery } from 'data/edge-functions/edge-functions-query' import { useReadReplicasQuery } from 'data/read-replicas/replicas-query' import { useTablesQuery } from 'data/tables/tables-query' +import { useIsFeatureEnabled } from 'hooks/misc/useIsFeatureEnabled' import { useSelectedOrganizationQuery } from 'hooks/misc/useSelectedOrganization' import { useIsOrioleDb, @@ -48,6 +50,23 @@ const Home: NextPageWithLayout = () => { const snap = useAppStateSnapshot() const { ref, enableBranching } = useParams() + const { + projectHomepageShowAllClientLibraries: showAllClientLibraries, + projectHomepageShowInstanceSize: showInstanceSize, + projectHomepageShowExamples: showExamples, + } = useIsFeatureEnabled([ + 'project_homepage:show_all_client_libraries', + 'project_homepage:show_instance_size', + 'project_homepage:show_examples', + ]) + + const clientLibraries = useMemo(() => { + if (showAllClientLibraries) { + return CLIENT_LIBRARIES + } + return CLIENT_LIBRARIES.filter((library) => library.language === 'JavaScript') + }, [showAllClientLibraries]) + const hasShownEnableBranchingModalRef = useRef(false) const isPaused = project?.status === PROJECT_STATUS.INACTIVE const isNewProject = dayjs(project?.inserted_at).isAfter(dayjs().subtract(2, 'day')) @@ -125,14 +144,16 @@ const Home: NextPageWithLayout = () => { )} - + {showInstanceSize && ( + + )}
@@ -221,42 +242,44 @@ const Home: NextPageWithLayout = () => {

Client libraries

- {CLIENT_LIBRARIES.map((library) => ( + {clientLibraries.map((library) => ( ))}
-
-

Example projects

-
- - - App Frameworks - - Mobile Frameworks - - - -
- {EXAMPLE_PROJECTS.filter((project) => project.type === 'app') - .sort((a, b) => a.title.localeCompare(b.title)) - .map((project) => ( - - ))} -
-
- -
- {EXAMPLE_PROJECTS.filter((project) => project.type === 'mobile') - .sort((a, b) => a.title.localeCompare(b.title)) - .map((project) => ( - - ))} -
-
-
+ {showExamples && ( +
+

Example projects

+
+ + + App Frameworks + + Mobile Frameworks + + + +
+ {EXAMPLE_PROJECTS.filter((project) => project.type === 'app') + .sort((a, b) => a.title.localeCompare(b.title)) + .map((project) => ( + + ))} +
+
+ +
+ {EXAMPLE_PROJECTS.filter((project) => project.type === 'mobile') + .sort((a, b) => a.title.localeCompare(b.title)) + .map((project) => ( + + ))} +
+
+
+
-
+ )} )}
diff --git a/packages/common/enabled-features/enabled-features.json b/packages/common/enabled-features/enabled-features.json index 7e89886356f..abdb1d71d7f 100644 --- a/packages/common/enabled-features/enabled-features.json +++ b/packages/common/enabled-features/enabled-features.json @@ -5,5 +5,14 @@ "logs:collections": true, "profile:show_email": true, - "profile:update": true + "profile:show_information": true, + + "project_connection:javascript_example": true, + "project_connection:dart_example": true, + + "project_creation:show_advanced_config": true, + + "project_homepage:show_all_client_libraries": true, + "project_homepage:show_instance_size": true, + "project_homepage:show_examples": true } diff --git a/packages/common/enabled-features/enabled-features.schema.json b/packages/common/enabled-features/enabled-features.schema.json index 1d3ffa384d4..317fca868b2 100644 --- a/packages/common/enabled-features/enabled-features.schema.json +++ b/packages/common/enabled-features/enabled-features.schema.json @@ -19,11 +19,49 @@ "type": "boolean", "description": "Show the user's email address in the toolbar" }, - "profile:update": { + "profile:show_information": { "type": "boolean", - "description": "Allow the user to change their profile information (first name, last name)" + "description": "Shows the user's profile information (first name, last name) in account preferences" + }, + + "project_connection:javascript_example": { + "type": "boolean", + "description": "Show the javascript example in the project connection settings" + }, + "project_connection:dart_example": { + "type": "boolean", + "description": "Show the dart example in the project connection settings" + }, + + "project_creation:show_advanced_config": { + "type": "boolean", + "description": "Show the advanced configuration option in the project creation flow" + }, + + "project_homepage:show_instance_size": { + "type": "boolean", + "description": "Show the instance size badge in the project homepage" + }, + "project_homepage:show_examples": { + "type": "boolean", + "description": "Show the example projects in the project homepage" + }, + "project_homepage:show_all_client_libraries": { + "type": "boolean", + "description": "Show all client libraries examples in the project homepage. When false, all client library examples will be hidden except the JavaScript client library." } }, - "required": ["profile:show_email", "profile:update", "logs:templates", "logs:collections"], + "required": [ + "profile:show_email", + "profile:show_information", + "logs:templates", + "logs:collections", + "project_creation:show_advanced_config", + "project_homepage:show_instance_size", + "project_homepage:show_examples", + "project_homepage:show_all_client_libraries", + "project_connection:javascript_example", + "project_connection:dart_example" + ], "additionalProperties": false }