mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 09:25:06 +03:00
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 <joshenlimek@gmail.com>
This commit is contained in:
1 parent
71ba2126a5
commit
be45baf6c4
10 files changed
+198
-98
No files matched your search
@@ -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<void> 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 (
|
||||
<Panel
|
||||
@@ -177,34 +188,34 @@ const APIKeys = () => {
|
||||
}
|
||||
/>
|
||||
</Panel.Content>
|
||||
<div className="border-t border-panel-border-interior-light dark:border-panel-border-interior-dark">
|
||||
<div className="flex items-center bg-studio">
|
||||
{availableLanguages.map((language) => {
|
||||
const isSelected = selectedLanguage.key === language.key
|
||||
return (
|
||||
<div
|
||||
key={language.key}
|
||||
className={[
|
||||
'px-3 py-1 text-sm cursor-pointer transition',
|
||||
`${!isSelected ? 'bg-studio text-foreground-light' : 'bg-surface-100'}`,
|
||||
].join(' ')}
|
||||
onClick={() => setSelectedLanguage(language)}
|
||||
>
|
||||
{language.name}
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
{availableLanguages.length > 0 && (
|
||||
<div className="border-t border-panel-border-interior-light dark:border-panel-border-interior-dark">
|
||||
<div className="flex items-center bg-studio">
|
||||
{availableLanguages.map((language) => {
|
||||
const isSelected = selectedLanguage.key === language.key
|
||||
return (
|
||||
<div
|
||||
key={language.key}
|
||||
className={[
|
||||
'px-3 py-1 text-sm cursor-pointer transition',
|
||||
`${!isSelected ? 'bg-studio text-foreground-light' : 'bg-surface-100'}`,
|
||||
].join(' ')}
|
||||
onClick={() => setSelectedLanguage(language)}
|
||||
>
|
||||
{language.name}
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
<div className="bg-surface-100 px-4 py-6 min-h-[200px]">
|
||||
<SimpleCodeBlock className={selectedLanguage.key}>
|
||||
{selectedLanguageSnippet}
|
||||
</SimpleCodeBlock>
|
||||
</div>
|
||||
</div>
|
||||
<div className="bg-surface-100 px-4 py-6 min-h-[200px]">
|
||||
<SimpleCodeBlock className={selectedLanguage.key}>
|
||||
{selectedLanguageSnippet}
|
||||
</SimpleCodeBlock>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</Panel>
|
||||
)
|
||||
}
|
||||
|
||||
export default APIKeys
|
||||
@@ -31,7 +31,7 @@ const Row = ({
|
||||
</div>
|
||||
)
|
||||
|
||||
const GetStartedHero = () => {
|
||||
export const GetStartedHero = () => {
|
||||
return (
|
||||
<div className="w-full max-w-[500px] h-full pb-10 lg:pb-0 relative pointer-events-none">
|
||||
<div
|
||||
@@ -105,5 +105,3 @@ const GetStartedHero = () => {
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default GetStartedHero
|
||||
@@ -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 = () => {
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default NewProjectPanel
|
||||
@@ -1,3 +1,2 @@
|
||||
export { default as ClientLibrary } from './ClientLibrary'
|
||||
export { default as ExampleProject } from './ExampleProject'
|
||||
export { default as NewProjectPanel } from './NewProjectPanel/NewProjectPanel'
|
||||
@@ -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 = () => {
|
||||
<h4 className="text-lg">Client libraries</h4>
|
||||
</div>
|
||||
<div className="grid grid-cols-2 gap-x-8 gap-y-8 md:gap-12 mx-6 mb-12 md:grid-cols-3">
|
||||
{CLIENT_LIBRARIES.map((library) => (
|
||||
{clientLibraries.map((library) => (
|
||||
<ClientLibrary key={library.language} {...library} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-8">
|
||||
<div className="mx-6">
|
||||
<h5>Example projects</h5>
|
||||
{showExamples && (
|
||||
<div className="space-y-8">
|
||||
<div className="mx-6">
|
||||
<h5>Example projects</h5>
|
||||
</div>
|
||||
<div className="mx-6 grid gap-2 md:gap-8 md:grid-cols-2 lg:grid-cols-3">
|
||||
{EXAMPLE_PROJECTS.map((project) => (
|
||||
<ExampleProject key={project.url} {...project} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className="mx-6 grid gap-2 md:gap-8 md:grid-cols-2 lg:grid-cols-3">
|
||||
{EXAMPLE_PROJECTS.map((project) => (
|
||||
<ExampleProject key={project.url} {...project} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -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 ? <ProfileInformation /> : null}
|
||||
{profileShowInformation && isSuccess ? <ProfileInformation /> : null}
|
||||
<AccountIdentities />
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -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 = () => {
|
||||
)}
|
||||
|
||||
<SecurityOptions form={form} />
|
||||
{!!availableOrioleVersion && <AdvancedConfiguration form={form} />}
|
||||
{showAdvancedConfig && !!availableOrioleVersion && (
|
||||
<AdvancedConfiguration form={form} />
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
|
||||
@@ -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 = () => {
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
)}
|
||||
<ComputeBadgeWrapper
|
||||
project={{
|
||||
ref: project?.ref,
|
||||
organization_slug: organization?.slug,
|
||||
cloud_provider: project?.cloud_provider,
|
||||
infra_compute_size: project?.infra_compute_size,
|
||||
}}
|
||||
/>
|
||||
{showInstanceSize && (
|
||||
<ComputeBadgeWrapper
|
||||
project={{
|
||||
ref: project?.ref,
|
||||
organization_slug: organization?.slug,
|
||||
cloud_provider: project?.cloud_provider,
|
||||
infra_compute_size: project?.infra_compute_size,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center">
|
||||
@@ -221,42 +242,44 @@ const Home: NextPageWithLayout = () => {
|
||||
<div className="space-y-8">
|
||||
<h2 className="text-lg">Client libraries</h2>
|
||||
<div className="grid grid-cols-2 gap-x-8 gap-y-8 md:gap-12 mb-12 md:grid-cols-3">
|
||||
{CLIENT_LIBRARIES.map((library) => (
|
||||
{clientLibraries.map((library) => (
|
||||
<ClientLibrary key={library.language} {...library} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-8">
|
||||
<h4 className="text-lg">Example projects</h4>
|
||||
<div className="flex justify-center">
|
||||
<Tabs_Shadcn_ defaultValue="app" className="w-full">
|
||||
<TabsList_Shadcn_ className="flex gap-4 mb-8">
|
||||
<TabsTrigger_Shadcn_ value="app">App Frameworks</TabsTrigger_Shadcn_>
|
||||
<TabsTrigger_Shadcn_ value="mobile">
|
||||
Mobile Frameworks
|
||||
</TabsTrigger_Shadcn_>
|
||||
</TabsList_Shadcn_>
|
||||
<TabsContent_Shadcn_ value="app">
|
||||
<div className="grid gap-2 md:gap-8 md:grid-cols-2 lg:grid-cols-3">
|
||||
{EXAMPLE_PROJECTS.filter((project) => project.type === 'app')
|
||||
.sort((a, b) => a.title.localeCompare(b.title))
|
||||
.map((project) => (
|
||||
<ExampleProject key={project.url} {...project} />
|
||||
))}
|
||||
</div>
|
||||
</TabsContent_Shadcn_>
|
||||
<TabsContent_Shadcn_ value="mobile">
|
||||
<div className="grid gap-2 md:gap-8 md:grid-cols-2 lg:grid-cols-3">
|
||||
{EXAMPLE_PROJECTS.filter((project) => project.type === 'mobile')
|
||||
.sort((a, b) => a.title.localeCompare(b.title))
|
||||
.map((project) => (
|
||||
<ExampleProject key={project.url} {...project} />
|
||||
))}
|
||||
</div>
|
||||
</TabsContent_Shadcn_>
|
||||
</Tabs_Shadcn_>
|
||||
{showExamples && (
|
||||
<div className="space-y-8">
|
||||
<h4 className="text-lg">Example projects</h4>
|
||||
<div className="flex justify-center">
|
||||
<Tabs_Shadcn_ defaultValue="app" className="w-full">
|
||||
<TabsList_Shadcn_ className="flex gap-4 mb-8">
|
||||
<TabsTrigger_Shadcn_ value="app">App Frameworks</TabsTrigger_Shadcn_>
|
||||
<TabsTrigger_Shadcn_ value="mobile">
|
||||
Mobile Frameworks
|
||||
</TabsTrigger_Shadcn_>
|
||||
</TabsList_Shadcn_>
|
||||
<TabsContent_Shadcn_ value="app">
|
||||
<div className="grid gap-2 md:gap-8 md:grid-cols-2 lg:grid-cols-3">
|
||||
{EXAMPLE_PROJECTS.filter((project) => project.type === 'app')
|
||||
.sort((a, b) => a.title.localeCompare(b.title))
|
||||
.map((project) => (
|
||||
<ExampleProject key={project.url} {...project} />
|
||||
))}
|
||||
</div>
|
||||
</TabsContent_Shadcn_>
|
||||
<TabsContent_Shadcn_ value="mobile">
|
||||
<div className="grid gap-2 md:gap-8 md:grid-cols-2 lg:grid-cols-3">
|
||||
{EXAMPLE_PROJECTS.filter((project) => project.type === 'mobile')
|
||||
.sort((a, b) => a.title.localeCompare(b.title))
|
||||
.map((project) => (
|
||||
<ExampleProject key={project.url} {...project} />
|
||||
))}
|
||||
</div>
|
||||
</TabsContent_Shadcn_>
|
||||
</Tabs_Shadcn_>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
Reference in new issue
Block a user