Chore/cleanup feature flags 041224 (#30885)

* Deprecate enableFreeSupport flag

* Deprecate enableExperimentalTheme flag and ThemeSettingsOld component

* Deprecate httpsAuthHooksEnabled flag

* Deprecate thirdPartyAuth flag

* Deprecate logdrains flag

* Deprecate enableNewRegions flag

* Deprecate cronUi flag

* Deprecate queues flag and old ProjectIntegrationsLayout folder
This commit is contained in:
Joshen Lim authored and GitHub committed 2024-12-04 17:04:53 +08:00
1 parent d265797541
commit fdf4dec344
12 files changed
+265 -614

No files matched your search

@@ -1,54 +0,0 @@
import { Moon, Sun } from 'lucide-react'
import { useTheme } from 'next-themes'
import { useEffect, useState } from 'react'
import Panel from 'components/ui/Panel'
import { Listbox, Theme, themes } from 'ui'
const ThemeSettings = () => {
const [mounted, setMounted] = useState(false)
const { theme, resolvedTheme, setTheme } = useTheme()
/**
* Avoid Hydration Mismatch
* https://github.com/pacocoursey/next-themes?tab=readme-ov-file#avoid-hydration-mismatch
*/
// useEffect only runs on the client, so now we can safely show the UI
useEffect(() => {
setMounted(true)
}, [])
if (!mounted) {
return null
}
return (
<Panel title={<h5 key="panel-title">Theme</h5>}>
<Panel.Content>
<Listbox
value={theme}
label="Interface theme"
descriptionText="Choose a theme preference"
layout="horizontal"
style={{ width: '50%' }}
icon={resolvedTheme === 'dark' ? <Moon /> : <Sun />}
onChange={(value: string) => setTheme(value)}
>
{themes
.filter(
(theme: Theme) =>
// temporary fix to exclude new themes
theme.value === 'light' || theme.value === 'dark' || theme.value === 'system'
)
.map((theme: Theme) => (
<Listbox.Option key={theme.value} label={theme.name} value={theme.value}>
{theme.name}
</Listbox.Option>
))}
</Listbox>
</Panel.Content>
</Panel>
)
}
export default ThemeSettings
@@ -1,4 +1,3 @@
export { default as AccountInformation } from './AccountInformation'
export { default as AnalyticsSettings } from './AnalyticsSettings'
export { default as ThemeSettingsOld } from './ThemeSettingsOld'
export { default as ThemeSettings } from './ThemeSettings'
@@ -16,7 +16,6 @@ import SchemaSelector from 'components/ui/SchemaSelector'
import { AuthConfigResponse } from 'data/auth/auth-config-query'
import { useAuthHooksUpdateMutation } from 'data/auth/auth-hooks-update-mutation'
import { executeSql } from 'data/sql/execute-sql-query'
import { useFlag } from 'hooks/ui/useFlag'
import {
Button,
FormControl_Shadcn_,
@@ -116,7 +115,6 @@ export const CreateHookSheet = ({
}: CreateHookSheetProps) => {
const { ref: projectRef } = useParams()
const { project } = useProjectContext()
const httpsAuthHooksEnabled = useFlag('httpsAuthHooksEnabled')
const definition = useMemo(
() => HOOKS_DEFINITIONS.find((d) => d.title === title) || HOOKS_DEFINITIONS[0],
@@ -326,37 +324,35 @@ export const CreateHookSheet = ({
)}
/>
<Separator />
{httpsAuthHooksEnabled && (
<FormField_Shadcn_
control={form.control}
name="selectedType"
render={({ field }) => (
<FormItemLayout label="Hook type" className="px-5">
<FormControl_Shadcn_>
<RadioGroupStacked
value={field.value}
onValueChange={(value) => field.onChange(value)}
>
<RadioGroupStackedItem
value="postgres"
id="postgres"
key="postgres"
label="Postgres"
description="Used to call a Postgres function."
/>
<RadioGroupStackedItem
value="https"
id="https"
key="https"
label="HTTPS"
description="Used to call any HTTPS endpoint."
/>
</RadioGroupStacked>
</FormControl_Shadcn_>
</FormItemLayout>
)}
/>
)}
<FormField_Shadcn_
control={form.control}
name="selectedType"
render={({ field }) => (
<FormItemLayout label="Hook type" className="px-5">
<FormControl_Shadcn_>
<RadioGroupStacked
value={field.value}
onValueChange={(value) => field.onChange(value)}
>
<RadioGroupStackedItem
value="postgres"
id="postgres"
key="postgres"
label="Postgres"
description="Used to call a Postgres function."
/>
<RadioGroupStackedItem
value="https"
id="https"
key="https"
label="HTTPS"
description="Used to call any HTTPS endpoint."
/>
</RadioGroupStacked>
</FormControl_Shadcn_>
</FormItemLayout>
)}
/>
{values.selectedType === 'postgres' ? (
<>
<div className="grid grid-cols-2 gap-8 px-5">
@@ -12,7 +12,6 @@ import {
useThirdPartyAuthIntegrationsQuery,
} from 'data/third-party-auth/integrations-query'
import { useCheckPermissions } from 'hooks/misc/useCheckPermissions'
import { useFlag } from 'hooks/ui/useFlag'
import { cn } from 'ui'
import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal'
import { AddIntegrationDropdown } from './AddIntegrationDropdown'
@@ -27,7 +26,6 @@ import {
} from './ThirdPartyAuthForm.utils'
export const ThirdPartyAuthForm = () => {
const thirdPartyAuthEnabled = useFlag('thirdPartyAuth')
const { ref: projectRef } = useParams()
const {
data: integrationsData,
@@ -45,10 +43,6 @@ export const ThirdPartyAuthForm = () => {
const { mutateAsync: deleteIntegration } = useDeleteThirdPartyAuthIntegrationMutation()
const canUpdateConfig = useCheckPermissions(PermissionAction.UPDATE, 'custom_config_gotrue')
if (!thirdPartyAuthEnabled) {
return null
}
if (isError) {
return (
<AlertError
@@ -2,7 +2,6 @@ import { useRouter } from 'next/router'
import { ControllerRenderProps, UseFormReturn } from 'react-hook-form'
import { useDefaultRegionQuery } from 'data/misc/get-default-region-query'
import { useFlag } from 'hooks/ui/useFlag'
import { PROVIDERS } from 'lib/constants'
import type { CloudProvider } from 'shared-data'
import {
@@ -28,17 +27,13 @@ interface RegionSelectorProps {
export const RegionSelector = ({ cloudProvider, field }: RegionSelectorProps) => {
const router = useRouter()
const newRegions = ['EAST_US_2', 'WEST_EU_3', 'CENTRAL_EU_2', 'NORTH_EU']
const enableNewRegions = useFlag('enableNewRegions')
const showNonProdFields =
process.env.NEXT_PUBLIC_ENVIRONMENT === 'local' ||
process.env.NEXT_PUBLIC_ENVIRONMENT === 'staging'
const availableRegions = getAvailableRegions(PROVIDERS[cloudProvider].id)
const regionsArray = enableNewRegions
? Object.entries(availableRegions)
: Object.entries(availableRegions).filter(([key]) => !newRegions.includes(key))
const regionsArray = Object.entries(availableRegions)
const { isLoading: isLoadingDefaultRegion } = useDefaultRegionQuery({
cloudProvider,
@@ -10,12 +10,13 @@ import * as z from 'zod'
import { useDocsSearch, useParams, type DocsSearchResult as Page } from 'common'
import { CLIENT_LIBRARIES } from 'common/constants'
import { getProjectAuthConfig } from 'data/auth/auth-config-query'
import { useSendSupportTicketMutation } from 'data/feedback/support-ticket-send'
import { useOrganizationsQuery } from 'data/organizations/organizations-query'
import type { Project } from 'data/projects/project-detail-query'
import { useProjectsQuery } from 'data/projects/projects-query'
import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query'
import { useFlag } from 'hooks/ui/useFlag'
import { detectBrowser } from 'lib/helpers'
import { useProfile } from 'lib/profile'
import {
Badge,
@@ -37,8 +38,10 @@ import {
TextArea_Shadcn_,
} from 'ui'
import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
import DisabledStateForFreeTier from './DisabledStateForFreeTier'
import { MultiSelectV2 } from 'ui-patterns/MultiSelectDeprecated/MultiSelectV2'
import { DocsLinkGroup } from './DocsLink'
import { IPV4SuggestionAlert } from './IPV4SuggestionAlert'
import { LibrarySuggestions } from './LibrarySuggestions'
import { PlanExpectationInfoBox } from './PlanExpectationInfoBox'
import {
CATEGORY_OPTIONS,
@@ -46,12 +49,7 @@ import {
SERVICE_OPTIONS,
SEVERITY_OPTIONS,
} from './Support.constants'
import { LibrarySuggestions } from './LibrarySuggestions'
import { MultiSelectV2 } from 'ui-patterns/MultiSelectDeprecated/MultiSelectV2'
import { IPV4SuggestionAlert } from './IPV4SuggestionAlert'
import { formatMessage, uploadAttachments } from './SupportForm.utils'
import { detectBrowser } from 'lib/helpers'
import { getProjectAuthConfig } from 'data/auth/auth-config-query'
const MAX_ATTACHMENTS = 5
const INCLUDE_DISCUSSIONS = ['Problem', 'Database_unresponsive']
@@ -68,7 +66,6 @@ export const SupportFormV2 = ({ setSentCategory, setSelectedProject }: SupportFo
const { profile } = useProfile()
const supabaseClient = useSupabaseClient()
const { ref, slug, category: urlCategory, subject: urlSubject, message: urlMessage } = useParams()
const enableFreeSupport = useFlag('enableFreeSupport')
const uploadButtonRef = useRef(null)
const [isSubmitting, setIsSubmitting] = useState(false)
@@ -486,250 +483,239 @@ export const SupportFormV2 = ({ setSentCategory, setSelectedProject }: SupportFo
<Separator />
{!enableFreeSupport || (category === 'Performance' && subscriptionPlanId === 'free') ? (
<DisabledStateForFreeTier
category={CATEGORY_OPTIONS.find((o) => o.value === category)?.label ?? ''}
organizationSlug={organizationSlug}
/>
) : (
<>
<div className={cn(CONTAINER_CLASSES, 'flex flex-col gap-y-2')}>
<FormField_Shadcn_
name="subject"
control={form.control}
render={({ field }) => (
<FormItemLayout
layout="vertical"
label="Subject"
description={
field.value.length > 0 &&
INCLUDE_DISCUSSIONS.includes(category) && (
<p className="flex items-center gap-x-1">
<span>Check our </span>
<Link
key="gh-discussions"
href={`https://github.com/orgs/supabase/discussions?discussions_q=${field.value}`}
target="_blank"
rel="noreferrer"
className="flex items-center gap-x-1 text-foreground-light underline hover:text-foreground transition"
>
Github discussions
<ExternalLink size={14} strokeWidth={2} />
</Link>
<span> for a quick answer</span>
</p>
)
}
>
<FormControl_Shadcn_>
<Input_Shadcn_ {...field} placeholder="Summary of the problem you have" />
</FormControl_Shadcn_>
</FormItemLayout>
)}
/>
{docsResults.length > 0 && hasResults && (
<div className="pt-4 px-4 border rounded-md">
<h2 className="text-sm text-foreground-light px-2 mb-4">
Suggested resources ({Math.min(docsResults.length, 5)})
</h2>
<ScrollArea className={docsResults.length > 3 ? 'h-[300px]' : ''}>
{docsResults.slice(0, 5).map((page, i) => (
<DocsLinkGroup key={`${page.id}-group`} page={page} />
))}
</ScrollArea>
</div>
)}
</div>
{category === 'Problem' && (
<FormField_Shadcn_
name="library"
control={form.control}
render={({ field }) => (
<FormItemLayout
className={cn(CONTAINER_CLASSES)}
layout="vertical"
label="Which library are you having issues with"
>
<FormControl_Shadcn_>
<Select_Shadcn_
{...field}
defaultValue={field.value}
onValueChange={field.onChange}
<div className={cn(CONTAINER_CLASSES, 'flex flex-col gap-y-2')}>
<FormField_Shadcn_
name="subject"
control={form.control}
render={({ field }) => (
<FormItemLayout
layout="vertical"
label="Subject"
description={
field.value.length > 0 &&
INCLUDE_DISCUSSIONS.includes(category) && (
<p className="flex items-center gap-x-1">
<span>Check our </span>
<Link
key="gh-discussions"
href={`https://github.com/orgs/supabase/discussions?discussions_q=${field.value}`}
target="_blank"
rel="noreferrer"
className="flex items-center gap-x-1 text-foreground-light underline hover:text-foreground transition"
>
<SelectTrigger_Shadcn_ className="w-full">
<SelectValue_Shadcn_ placeholder="Please select a library" />
</SelectTrigger_Shadcn_>
<SelectContent_Shadcn_>
<SelectGroup_Shadcn_>
{CLIENT_LIBRARIES.map((option) => (
<SelectItem_Shadcn_ value={option.language}>
{option.language}
</SelectItem_Shadcn_>
))}
</SelectGroup_Shadcn_>
</SelectContent_Shadcn_>
</Select_Shadcn_>
</FormControl_Shadcn_>
</FormItemLayout>
)}
/>
Github discussions
<ExternalLink size={14} strokeWidth={2} />
</Link>
<span> for a quick answer</span>
</p>
)
}
>
<FormControl_Shadcn_>
<Input_Shadcn_ {...field} placeholder="Summary of the problem you have" />
</FormControl_Shadcn_>
</FormItemLayout>
)}
/>
{library.length > 0 && <LibrarySuggestions library={library} />}
{category !== 'Login_issues' && (
<FormField_Shadcn_
name="affectedServices"
control={form.control}
render={({ field }) => (
<FormItemLayout
className={cn(CONTAINER_CLASSES)}
layout="vertical"
label="Which services are affected?"
>
<FormControl_Shadcn_>
<MultiSelectV2
options={SERVICE_OPTIONS}
value={field.value.length === 0 ? [] : field.value?.split(', ')}
placeholder="No particular service"
searchPlaceholder="Search for a service"
onChange={(services) =>
form.setValue('affectedServices', services.join(', '))
}
/>
</FormControl_Shadcn_>
</FormItemLayout>
)}
/>
)}
<FormField_Shadcn_
name="message"
control={form.control}
render={({ field }) => (
<FormItemLayout
className={cn(CONTAINER_CLASSES)}
layout="vertical"
label="Message"
labelOptional="5000 character limit"
description={
IPV4_MIGRATION_STRINGS.some((str) => field.value.includes(str)) && (
<IPV4SuggestionAlert />
)
}
>
<FormControl_Shadcn_>
<TextArea_Shadcn_
{...field}
rows={4}
maxLength={5000}
placeholder="Describe the issue you're facing, along with any relevant information. Please be as detailed and specific as possible."
/>
</FormControl_Shadcn_>
</FormItemLayout>
)}
/>
{['Problem', 'Database_unresponsive', 'Performance'].includes(category) && (
<FormField_Shadcn_
name="allowSupportAccess"
control={form.control}
render={({ field }) => (
<FormItemLayout
layout="flex"
className={cn(CONTAINER_CLASSES)}
label="Allow Supabase Support to access your project temporarily"
description="In some cases, we may require temporary access to your project to complete troubleshooting, or to answer questions related specifically to your project"
>
<FormControl_Shadcn_>
<Checkbox_Shadcn_
{...field}
value={String(field.value)}
checked={field.value}
onCheckedChange={(value) => field.onChange(value)}
/>
</FormControl_Shadcn_>
</FormItemLayout>
)}
/>
)}
<div className={cn(CONTAINER_CLASSES)}>
<div className="flex flex-col gap-y-1">
<p className="text-sm text-foreground-light">Attachments</p>
<p className="text-sm text-foreground-lighter">
Upload up to {MAX_ATTACHMENTS} screenshots that might be relevant to the issue
that you're facing
</p>
</div>
<input
multiple
type="file"
ref={uploadButtonRef}
className="hidden"
accept="image/png, image/jpeg"
onChange={onFilesUpload}
/>
<div className="flex items-center gap-x-2 mt-4">
{uploadedDataUrls.map((x: any, idx: number) => (
<div
key={idx}
style={{ backgroundImage: `url("${x}")` }}
className="relative h-14 w-14 rounded bg-cover bg-center bg-no-repeat"
>
<div
className={[
'flex h-4 w-4 items-center justify-center rounded-full bg-red-900',
'absolute -top-1 -right-1 cursor-pointer',
].join(' ')}
onClick={() => removeUploadedFile(idx)}
>
<X size={12} strokeWidth={2} />
</div>
</div>
{docsResults.length > 0 && hasResults && (
<div className="pt-4 px-4 border rounded-md">
<h2 className="text-sm text-foreground-light px-2 mb-4">
Suggested resources ({Math.min(docsResults.length, 5)})
</h2>
<ScrollArea className={docsResults.length > 3 ? 'h-[300px]' : ''}>
{docsResults.slice(0, 5).map((page, i) => (
<DocsLinkGroup key={`${page.id}-group`} page={page} />
))}
{uploadedFiles.length < MAX_ATTACHMENTS && (
<div
className={[
'border border-stronger opacity-50 transition hover:opacity-100',
'group flex h-14 w-14 cursor-pointer items-center justify-center rounded',
].join(' ')}
onClick={() => {
if (uploadButtonRef.current) (uploadButtonRef.current as any).click()
}}
>
<Plus strokeWidth={2} size={20} />
</div>
)}
</div>
</ScrollArea>
</div>
)}
</div>
<div className={cn(CONTAINER_CLASSES)}>
<div className="flex items-center space-x-1 justify-end block text-sm mt-0 mb-2">
<p className="text-foreground-light">We will contact you at</p>
<p className="text-foreground font-medium">{respondToEmail}</p>
</div>
<div className="flex items-center space-x-1 justify-end block text-sm mt-0 mb-2">
<p className="text-foreground-light">
Please ensure you haven't blocked Hubspot in your emails
</p>
</div>
<div className="flex justify-end">
<Button
htmlType="submit"
size="small"
icon={<Mail />}
disabled={isSubmitting}
loading={isSubmitting}
>
Send support request
</Button>
</div>
</div>
</>
{category === 'Problem' && (
<FormField_Shadcn_
name="library"
control={form.control}
render={({ field }) => (
<FormItemLayout
className={cn(CONTAINER_CLASSES)}
layout="vertical"
label="Which library are you having issues with"
>
<FormControl_Shadcn_>
<Select_Shadcn_
{...field}
defaultValue={field.value}
onValueChange={field.onChange}
>
<SelectTrigger_Shadcn_ className="w-full">
<SelectValue_Shadcn_ placeholder="Please select a library" />
</SelectTrigger_Shadcn_>
<SelectContent_Shadcn_>
<SelectGroup_Shadcn_>
{CLIENT_LIBRARIES.map((option) => (
<SelectItem_Shadcn_ value={option.language}>
{option.language}
</SelectItem_Shadcn_>
))}
</SelectGroup_Shadcn_>
</SelectContent_Shadcn_>
</Select_Shadcn_>
</FormControl_Shadcn_>
</FormItemLayout>
)}
/>
)}
{library.length > 0 && <LibrarySuggestions library={library} />}
{category !== 'Login_issues' && (
<FormField_Shadcn_
name="affectedServices"
control={form.control}
render={({ field }) => (
<FormItemLayout
className={cn(CONTAINER_CLASSES)}
layout="vertical"
label="Which services are affected?"
>
<FormControl_Shadcn_>
<MultiSelectV2
options={SERVICE_OPTIONS}
value={field.value.length === 0 ? [] : field.value?.split(', ')}
placeholder="No particular service"
searchPlaceholder="Search for a service"
onChange={(services) => form.setValue('affectedServices', services.join(', '))}
/>
</FormControl_Shadcn_>
</FormItemLayout>
)}
/>
)}
<FormField_Shadcn_
name="message"
control={form.control}
render={({ field }) => (
<FormItemLayout
className={cn(CONTAINER_CLASSES)}
layout="vertical"
label="Message"
labelOptional="5000 character limit"
description={
IPV4_MIGRATION_STRINGS.some((str) => field.value.includes(str)) && (
<IPV4SuggestionAlert />
)
}
>
<FormControl_Shadcn_>
<TextArea_Shadcn_
{...field}
rows={4}
maxLength={5000}
placeholder="Describe the issue you're facing, along with any relevant information. Please be as detailed and specific as possible."
/>
</FormControl_Shadcn_>
</FormItemLayout>
)}
/>
{['Problem', 'Database_unresponsive', 'Performance'].includes(category) && (
<FormField_Shadcn_
name="allowSupportAccess"
control={form.control}
render={({ field }) => (
<FormItemLayout
layout="flex"
className={cn(CONTAINER_CLASSES)}
label="Allow Supabase Support to access your project temporarily"
description="In some cases, we may require temporary access to your project to complete troubleshooting, or to answer questions related specifically to your project"
>
<FormControl_Shadcn_>
<Checkbox_Shadcn_
{...field}
value={String(field.value)}
checked={field.value}
onCheckedChange={(value) => field.onChange(value)}
/>
</FormControl_Shadcn_>
</FormItemLayout>
)}
/>
)}
<div className={cn(CONTAINER_CLASSES)}>
<div className="flex flex-col gap-y-1">
<p className="text-sm text-foreground-light">Attachments</p>
<p className="text-sm text-foreground-lighter">
Upload up to {MAX_ATTACHMENTS} screenshots that might be relevant to the issue that
you're facing
</p>
</div>
<input
multiple
type="file"
ref={uploadButtonRef}
className="hidden"
accept="image/png, image/jpeg"
onChange={onFilesUpload}
/>
<div className="flex items-center gap-x-2 mt-4">
{uploadedDataUrls.map((x: any, idx: number) => (
<div
key={idx}
style={{ backgroundImage: `url("${x}")` }}
className="relative h-14 w-14 rounded bg-cover bg-center bg-no-repeat"
>
<div
className={[
'flex h-4 w-4 items-center justify-center rounded-full bg-red-900',
'absolute -top-1 -right-1 cursor-pointer',
].join(' ')}
onClick={() => removeUploadedFile(idx)}
>
<X size={12} strokeWidth={2} />
</div>
</div>
))}
{uploadedFiles.length < MAX_ATTACHMENTS && (
<div
className={[
'border border-stronger opacity-50 transition hover:opacity-100',
'group flex h-14 w-14 cursor-pointer items-center justify-center rounded',
].join(' ')}
onClick={() => {
if (uploadButtonRef.current) (uploadButtonRef.current as any).click()
}}
>
<Plus strokeWidth={2} size={20} />
</div>
)}
</div>
</div>
<div className={cn(CONTAINER_CLASSES)}>
<div className="flex items-center space-x-1 justify-end block text-sm mt-0 mb-2">
<p className="text-foreground-light">We will contact you at</p>
<p className="text-foreground font-medium">{respondToEmail}</p>
</div>
<div className="flex items-center space-x-1 justify-end block text-sm mt-0 mb-2">
<p className="text-foreground-light">
Please ensure you haven't blocked Hubspot in your emails
</p>
</div>
<div className="flex justify-end">
<Button
htmlType="submit"
size="small"
icon={<Mail />}
disabled={isSubmitting}
loading={isSubmitting}
>
Send support request
</Button>
</div>
</div>
</form>
</Form_Shadcn_>
)
@@ -1,107 +0,0 @@
import { Code } from 'lucide-react'
import { COMMAND_MENU_SECTIONS } from 'components/interfaces/App/CommandMenu/CommandMenu.utils'
import type { CommandOptions } from 'ui-patterns/CommandMenu'
import { useRegisterCommands } from 'ui-patterns/CommandMenu'
import { useParams } from 'common'
import { orderCommandSectionsByPriority } from 'components/interfaces/App/CommandMenu/ordering'
export function useDatabaseGotoCommands(options?: CommandOptions) {
let { ref } = useParams()
ref ||= '_'
useRegisterCommands(
COMMAND_MENU_SECTIONS.QUERY,
[
{
id: 'run-sql',
name: 'Run SQL',
route: `/project/${ref}/sql/new`,
icon: () => <Code />,
},
],
{
...options,
deps: [ref],
orderSection: orderCommandSectionsByPriority,
sectionMeta: { priority: 2 },
}
)
useRegisterCommands(
COMMAND_MENU_SECTIONS.NAVIGATE,
[
{
id: 'nav-database-tables',
name: 'Tables',
value: 'Database: Tables',
route: `/project/${ref}/database/tables`,
defaultHidden: true,
},
{
id: 'nav-database-triggers',
name: 'Triggers',
value: 'Database: Triggers',
route: `/project/${ref}/database/triggers`,
defaultHidden: true,
},
{
id: 'nav-database-functions',
name: 'Functions',
value: 'Database: Functions',
route: `/project/${ref}/database/functions`,
defaultHidden: true,
},
{
id: 'nav-database-extensions',
name: 'Extensions',
value: 'Database: Extensions',
route: `/project/${ref}/database/extensions`,
defaultHidden: true,
},
{
id: 'nav-database-roles',
name: 'Roles',
value: 'Database: Roles',
route: `/project/${ref}/database/roles`,
defaultHidden: true,
},
{
id: 'nav-database-replication',
name: 'Replication',
value: 'Database: Replication',
route: `/project/${ref}/database/replication`,
defaultHidden: true,
},
{
id: 'nav-database-hooks',
name: 'Webhooks',
value: 'Database: Webhooks',
route: `/project/${ref}/integrations/hooks`,
defaultHidden: true,
},
{
id: 'nav-database-backups',
name: 'Backups',
value: 'Database: Backups',
route: `/project/${ref}/database/backups/scheduled`,
defaultHidden: true,
},
{
id: 'nav-database-wrappers',
name: 'Wrappers',
value: 'Database: Wrappers',
route: `/project/${ref}/integrations/wrappers`,
defaultHidden: true,
},
{
id: 'nav-database-migrations',
name: 'Migrations',
value: 'Database: Migrations',
route: `/project/${ref}/database/migrations`,
defaultHidden: true,
},
],
{ ...options, deps: [ref] }
)
}
@@ -1,67 +0,0 @@
import { useRouter } from 'next/router'
import { PropsWithChildren } from 'react'
import { IS_PLATFORM } from 'common'
import { ProductMenu } from 'components/ui/ProductMenu'
import { useDatabaseExtensionsQuery } from 'data/database-extensions/database-extensions-query'
import { useSelectedProject } from 'hooks/misc/useSelectedProject'
import { withAuth } from 'hooks/misc/withAuth'
import { useFlag } from 'hooks/ui/useFlag'
import ProjectLayout from '../ProjectLayout/ProjectLayout'
import { generateProjectIntegrationsMenu } from './ProjectIntegrationsMenu.utils'
export interface ProjectIntegrationsLayoutProps {
title: string
}
const ProjectIntegrationsMenu = () => {
// if running on self-hosted, cron UI should be always enabled
const cronUiEnabled = useFlag('cronUi') || !IS_PLATFORM
const queuesUiEnabled = useFlag('queues')
const project = useSelectedProject()
const router = useRouter()
const page = router.pathname.split('/')[4]
const { data } = useDatabaseExtensionsQuery({
projectRef: project?.ref,
connectionString: project?.connectionString,
})
const pgNetExtensionExists = (data ?? []).find((ext) => ext.name === 'pg_net') !== undefined
const graphqlExtensionExists = (data ?? []).find((ext) => ext.name === 'pg_graphql') !== undefined
const pgmqExtensionExists = (data ?? []).find((ext) => ext.name === 'pgmq') !== undefined
return (
<>
<ProductMenu
page={page}
menu={generateProjectIntegrationsMenu(project, {
pgNetExtensionExists,
cronUiEnabled,
queuesUiEnabled,
graphqlExtensionExists,
pgmqExtensionExists,
})}
/>
</>
)
}
const ProjectIntegrationsLayout = ({
children,
title,
}: PropsWithChildren<ProjectIntegrationsLayoutProps>) => {
return (
<ProjectLayout
title={title}
product="Integrations"
productMenu={<ProjectIntegrationsMenu />}
isBlocking={false}
>
{children}
</ProjectLayout>
)
}
export default withAuth(ProjectIntegrationsLayout)
@@ -1,84 +0,0 @@
import type { ProductMenuGroup } from 'components/ui/ProductMenu/ProductMenu.types'
import type { Project } from 'data/projects/project-detail-query'
export const generateProjectIntegrationsMenu = (
project?: Project,
flags?: {
pgNetExtensionExists: boolean
cronUiEnabled: boolean
queuesUiEnabled: boolean
graphqlExtensionExists: boolean
pgmqExtensionExists: boolean
}
): ProductMenuGroup[] => {
const ref = project?.ref ?? 'default'
const {
pgNetExtensionExists,
cronUiEnabled,
queuesUiEnabled,
graphqlExtensionExists,
pgmqExtensionExists,
} = flags || {}
return [
{
title: 'Manage',
items: [
{
name: 'Wrappers',
key: 'wrappers',
url: `/project/${ref}/integrations/wrappers`,
items: [],
},
...(!!pgNetExtensionExists
? [
{
name: 'Webhooks',
key: 'hooks',
url: `/project/${ref}/integrations/hooks`,
items: [],
},
]
: []),
...(!!cronUiEnabled
? [
{
name: 'Cron',
key: 'cron-jobs',
url: `/project/${ref}/integrations/cron`,
items: [],
},
]
: []),
...(!!graphqlExtensionExists
? [
{
name: 'GraphiQL',
key: 'graphiql',
url: `/project/${ref}/integrations/graphiql`,
items: [],
},
]
: []),
{
name: 'Vault',
key: 'vault',
url: `/project/${ref}/integrations/vault/secrets`,
items: [],
label: 'BETA',
},
...(!!(queuesUiEnabled && pgmqExtensionExists)
? [
{
name: 'Queues',
key: 'queues',
url: `/project/${ref}/integrations/queues`,
items: [],
},
]
: []),
],
},
]
}
@@ -47,7 +47,6 @@ const SettingsLayout = ({ title, children }: PropsWithChildren<SettingsLayoutPro
])
const warehouseEnabled = useFlag('warehouse')
const logDrainsEnabled = useFlag('logdrains')
const diskAndComputeEnabled = useFlag('diskAndComputeForm')
const menuRoutes = generateSettingsMenu(ref, project, organization, {
@@ -56,7 +55,6 @@ const SettingsLayout = ({ title, children }: PropsWithChildren<SettingsLayoutPro
storage: storageEnabled,
invoices: invoicesEnabled,
warehouse: warehouseEnabled,
logDrains: logDrainsEnabled,
diskAndCompute: diskAndComputeEnabled,
})
@@ -15,7 +15,6 @@ export const generateSettingsMenu = (
storage?: boolean
invoices?: boolean
warehouse?: boolean
logDrains?: boolean
diskAndCompute?: boolean
}
): ProductMenuGroup[] => {
@@ -26,7 +25,6 @@ export const generateSettingsMenu = (
const edgeFunctionsEnabled = features?.edgeFunctions ?? true
const storageEnabled = features?.storage ?? true
const warehouseEnabled = features?.warehouse ?? false
const logDrainsEnabled = features?.logDrains ?? false
const newDiskComputeEnabled = features?.diskAndCompute ?? false
return [
@@ -136,7 +134,7 @@ export const generateSettingsMenu = (
},
]
: []),
...(IS_PLATFORM && logDrainsEnabled
...(IS_PLATFORM
? [
{
name: `Log Drains`,
+3 -6
View File
@@ -2,7 +2,6 @@ import {
AccountInformation,
AnalyticsSettings,
ThemeSettings,
ThemeSettingsOld,
} from 'components/interfaces/Account/Preferences'
import { AccountDeletion } from 'components/interfaces/Account/Preferences/AccountDeletion'
import { ProfileInformation } from 'components/interfaces/Account/Preferences/ProfileInformation'
@@ -11,7 +10,6 @@ import AlertError from 'components/ui/AlertError'
import Panel from 'components/ui/Panel'
import { GenericSkeletonLoader } from 'components/ui/ShimmeringLoader'
import { useIsFeatureEnabled } from 'hooks/misc/useIsFeatureEnabled'
import { useFlag } from 'hooks/ui/useFlag'
import { useProfile } from 'lib/profile'
import type { NextPageWithLayout } from 'types'
@@ -41,11 +39,8 @@ export default User
const ProfileCard = () => {
const profileUpdateEnabled = useIsFeatureEnabled('profile:update')
const { profile, error, isLoading, isError, isSuccess } = useProfile()
const experimentalThemeEnabled = useFlag('enableExperimentalTheme')
return (
<article className="max-w-4xl p-4">
{isLoading && (
@@ -71,7 +66,9 @@ const ProfileCard = () => {
</>
)}
<section>{experimentalThemeEnabled ? <ThemeSettings /> : <ThemeSettingsOld />}</section>
<section>
<ThemeSettings />
</section>
<section>
<AnalyticsSettings />