diff --git a/apps/docs/components/Navigation/NavigationMenu/MenuIcons.tsx b/apps/docs/components/Navigation/NavigationMenu/MenuIcons.tsx
index 7306d2c55a286..dd0667b168479 100644
--- a/apps/docs/components/Navigation/NavigationMenu/MenuIcons.tsx
+++ b/apps/docs/components/Navigation/NavigationMenu/MenuIcons.tsx
@@ -684,7 +684,7 @@ export function IconUI({ width = 16, height = 16, className }: HomeMenuIcon) {
height="14.72"
rx="1.92"
stroke="currentColor"
- stroke-width="1.28"
+ strokeWidth="1.28"
/>
{
const commands = useMemo(
() =>
[
- {
- id: 'support',
- name: 'Support',
- route: 'https://www.supabase.com/support',
- icon: () => ,
- },
{
id: 'system-status',
- name: 'System Status',
- value: 'Support: System Status',
+ name: 'View system status',
+ value: 'Support: View system status',
route: 'https://status.supabase.com',
+ icon: () => ,
+ },
+ {
+ id: 'discord-community',
+ name: 'Ask Discord community',
+ value: 'Support: Ask Discord community',
+ route: 'https://discord.supabase.com',
icon: () => ,
},
{
- id: 'github-discussions',
- name: 'GitHub Discussions',
- value: 'Support: GitHub Discussions',
- route: 'https://github.com/orgs/supabase/discussions',
+ id: 'support-team',
+ name: 'Contact support',
+ value: 'Support: Contact support',
+ route: 'https://www.supabase.com/support',
icon: () => ,
- defaultHidden: true,
},
] as Array,
[]
diff --git a/apps/studio/components/interfaces/Auth/AuthTemplatesValidation.tsx b/apps/studio/components/interfaces/Auth/AuthTemplatesValidation.tsx
index 390ba87c0e730..bf09377ebed02 100644
--- a/apps/studio/components/interfaces/Auth/AuthTemplatesValidation.tsx
+++ b/apps/studio/components/interfaces/Auth/AuthTemplatesValidation.tsx
@@ -9,7 +9,8 @@ const CONFIRMATION: FormSchema = {
$schema: JSON_SCHEMA_VERSION,
id: 'CONFIRMATION',
type: 'object',
- title: 'Confirm signup',
+ title: 'Confirm sign up',
+ purpose: 'Email verification for new user registrations',
properties: {
MAILER_SUBJECTS_CONFIRMATION: {
title: 'Subject heading',
@@ -20,7 +21,7 @@ const CONFIRMATION: FormSchema = {
descriptionOptional: 'HTML body of your email',
type: 'code',
description: `
-- \`{{ .ConfirmationURL }}\` : URL to confirm the e-mail address for the new account
+- \`{{ .ConfirmationURL }}\` : URL to confirm the email address for the new account
- \`{{ .Token }}\` : The 6-digit numeric email OTP
- \`{{ .TokenHash }}\` : The hashed token used in the URL
- \`{{ .SiteURL }}\` : The URL of the site
@@ -45,6 +46,7 @@ const INVITE: FormSchema = {
id: 'INVITE',
type: 'object',
title: 'Invite user',
+ purpose: "Allows administrators to invite users who don't have accounts yet",
properties: {
MAILER_SUBJECTS_INVITE: {
title: 'Subject heading',
@@ -79,7 +81,8 @@ const MAGIC_LINK: FormSchema = {
$schema: JSON_SCHEMA_VERSION,
id: 'MAGIC_LINK',
type: 'object',
- title: 'Magic Link',
+ title: 'Magic link',
+ purpose: 'Passwordless login using email links',
properties: {
MAILER_SUBJECTS_MAGIC_LINK: {
title: 'Subject heading',
@@ -114,7 +117,8 @@ const EMAIL_CHANGE: FormSchema = {
$schema: JSON_SCHEMA_VERSION,
id: 'EMAIL_CHANGE',
type: 'object',
- title: 'Change Email Address',
+ title: 'Change email address',
+ purpose: 'Verification for email address changes',
properties: {
MAILER_SUBJECTS_EMAIL_CHANGE: {
title: 'Subject heading',
@@ -150,7 +154,8 @@ const RECOVERY: FormSchema = {
$schema: JSON_SCHEMA_VERSION,
id: 'RECOVERY',
type: 'object',
- title: 'Reset Password',
+ title: 'Reset password',
+ purpose: 'Password recovery flow for users who forgot their password',
properties: {
MAILER_SUBJECTS_RECOVERY: {
title: 'Subject heading',
@@ -185,6 +190,8 @@ const REAUTHENTICATION: FormSchema = {
id: 'REAUTHENTICATION',
type: 'object',
title: 'Reauthentication',
+ purpose:
+ 'Additional verification for sensitive actions (like changing password, deleting account)',
properties: {
MAILER_SUBJECTS_REAUTHENTICATION: {
title: 'Subject heading',
diff --git a/apps/studio/components/interfaces/Auth/EmailRateLimitsAlert/EmailRateLimitsAlert.tsx b/apps/studio/components/interfaces/Auth/EmailRateLimitsAlert/EmailRateLimitsAlert.tsx
index 86c6a517ba116..09ea5b0e90820 100644
--- a/apps/studio/components/interfaces/Auth/EmailRateLimitsAlert/EmailRateLimitsAlert.tsx
+++ b/apps/studio/components/interfaces/Auth/EmailRateLimitsAlert/EmailRateLimitsAlert.tsx
@@ -3,34 +3,28 @@ import Link from 'next/link'
import { useParams } from 'common'
import { InlineLink } from 'components/ui/InlineLink'
import { DOCS_URL } from 'lib/constants'
-import {
- AlertDescription_Shadcn_,
- AlertTitle_Shadcn_,
- Alert_Shadcn_,
- Button,
- WarningIcon,
-} from 'ui'
+import { Button } from 'ui'
+import { Admonition } from 'ui-patterns/admonition'
export function EmailRateLimitsAlert() {
const { ref } = useParams()
return (
-
-
- Email rate-limits and restrictions
-
- You're using the built-in email service. The service has rate limits and it's not meant to
- be used for production apps. Check the{' '}
+
+
+ You’re using the built-in email service. This service has rate limits and is not meant to be
+ used for production apps.{' '}
- documentation
+ Learn more
{' '}
- for an up-to-date information on the current rate limits.
-
-
-
- Set up custom SMTP server
-
-
-
+
+
+ Set up SMTP
+
+
)
}
diff --git a/apps/studio/components/interfaces/Auth/EmailTemplates/EmailTemplates.tsx b/apps/studio/components/interfaces/Auth/EmailTemplates/EmailTemplates.tsx
index 71b8164e6948e..1f5c9921a48bd 100644
--- a/apps/studio/components/interfaces/Auth/EmailTemplates/EmailTemplates.tsx
+++ b/apps/studio/components/interfaces/Auth/EmailTemplates/EmailTemplates.tsx
@@ -1,13 +1,26 @@
import { useParams } from 'common'
+import { useIsSecurityNotificationsEnabled } from 'components/interfaces/App/FeaturePreview/FeaturePreviewContext'
+import { ScaffoldSection } from 'components/layouts/Scaffold'
import AlertError from 'components/ui/AlertError'
import { GenericSkeletonLoader } from 'components/ui/ShimmeringLoader'
import { useAuthConfigQuery } from 'data/auth/auth-config-query'
-import { Card, Tabs_Shadcn_, TabsContent_Shadcn_, TabsList_Shadcn_, TabsTrigger_Shadcn_ } from 'ui'
+import { ChevronRight } from 'lucide-react'
+import Link from 'next/link'
+import {
+ Card,
+ CardContent,
+ Tabs_Shadcn_,
+ TabsContent_Shadcn_,
+ TabsList_Shadcn_,
+ TabsTrigger_Shadcn_,
+} from 'ui'
import { TEMPLATES_SCHEMAS } from '../AuthTemplatesValidation'
import EmailRateLimitsAlert from '../EmailRateLimitsAlert'
+import { slugifyTitle } from './EmailTemplates.utils'
import TemplateEditor from './TemplateEditor'
export const EmailTemplates = () => {
+ const isSecurityNotificationsEnabled = useIsSecurityNotificationsEnabled()
const { ref: projectRef } = useParams()
const {
data: authConfig,
@@ -23,7 +36,7 @@ export const EmailTemplates = () => {
(!authConfig.SMTP_HOST || !authConfig.SMTP_USER || !authConfig.SMTP_PASS)
return (
-
) : null}
-
-
-
- {TEMPLATES_SCHEMAS.map((template) => {
- return (
-
- {template.title}
-
- )
- })}
-
+ {isSecurityNotificationsEnabled ? (
+
{TEMPLATES_SCHEMAS.map((template) => {
- const panelId = template.title.trim().replace(/\s+/g, '-')
+ const templateSlug = slugifyTitle(template.title)
return (
-
-
-
+
+
+
+
{template.title}
+ {template.purpose && (
+
{template.purpose}
+ )}
+
+
+
+
)
})}
-
-
+
+ ) : (
+
+
+
+ {TEMPLATES_SCHEMAS.map((template) => {
+ return (
+
+ {template.title}
+
+ )
+ })}
+
+ {TEMPLATES_SCHEMAS.map((template) => {
+ const panelId = slugifyTitle(template.title)
+ return (
+
+
+
+ )
+ })}
+
+
+ )}
)}
-
+
)
}
diff --git a/apps/studio/components/interfaces/Auth/EmailTemplates/EmailTemplates.utils.ts b/apps/studio/components/interfaces/Auth/EmailTemplates/EmailTemplates.utils.ts
new file mode 100644
index 0000000000000..e1297392939db
--- /dev/null
+++ b/apps/studio/components/interfaces/Auth/EmailTemplates/EmailTemplates.utils.ts
@@ -0,0 +1,8 @@
+/**
+ * Convert template title to URL-friendly slug
+ * Shared function to ensure slug matching works correctly across multiple files
+ * Necessary because TEMPLATES_SCHEMAS does not provide a slug for each template
+ */
+export const slugifyTitle = (title: string) => {
+ return title.trim().replace(/\s+/g, '-').toLowerCase()
+}
diff --git a/apps/studio/components/interfaces/Organization/CloudMarketplace/cloud-marketplace-query.ts b/apps/studio/components/interfaces/Organization/CloudMarketplace/cloud-marketplace-query.ts
index 0b9d924aa4c7e..359ee20aea595 100644
--- a/apps/studio/components/interfaces/Organization/CloudMarketplace/cloud-marketplace-query.ts
+++ b/apps/studio/components/interfaces/Organization/CloudMarketplace/cloud-marketplace-query.ts
@@ -42,9 +42,11 @@ export const useCloudMarketplaceOnboardingInfoQuery = = {}
) => {
const { profile } = useProfile()
- return useQuery(
- cloudMarketplaceKeys.onboardingInfo(buyerId),
- ({ signal }) => getCloudMarketplaceOnboardingInfo({ buyerId }, signal),
- { enabled: enabled && profile !== undefined, ...options, staleTime: 30 * 60 * 1000 }
- )
+ return useQuery({
+ queryKey: cloudMarketplaceKeys.onboardingInfo(buyerId),
+ queryFn: ({ signal }) => getCloudMarketplaceOnboardingInfo({ buyerId }, signal),
+ enabled: enabled && profile !== undefined,
+ ...options,
+ staleTime: 30 * 60 * 1000,
+ })
}
diff --git a/apps/studio/components/interfaces/Organization/HeaderBanner.tsx b/apps/studio/components/interfaces/Organization/HeaderBanner.tsx
index 9da5f4e65bda4..46dae901a5607 100644
--- a/apps/studio/components/interfaces/Organization/HeaderBanner.tsx
+++ b/apps/studio/components/interfaces/Organization/HeaderBanner.tsx
@@ -99,7 +99,7 @@ export const HeaderBanner = ({
{link && (
-
View Details
-
+
)}
diff --git a/apps/studio/components/interfaces/Organization/NewProject/FreeProjectLimitWarning.tsx b/apps/studio/components/interfaces/Organization/NewProject/FreeProjectLimitWarning.tsx
deleted file mode 100644
index 4aa43e5937ccc..0000000000000
--- a/apps/studio/components/interfaces/Organization/NewProject/FreeProjectLimitWarning.tsx
+++ /dev/null
@@ -1,38 +0,0 @@
-import { UpgradePlanButton } from 'components/ui/UpgradePlanButton'
-import type { MemberWithFreeProjectLimit } from 'data/organizations/free-project-limit-check-query'
-import { Admonition } from 'ui-patterns/admonition'
-
-interface FreeProjectLimitWarningProps {
- membersExceededLimit: MemberWithFreeProjectLimit[]
-}
-
-export const FreeProjectLimitWarning = ({ membersExceededLimit }: FreeProjectLimitWarningProps) => {
- return (
-
-
- The following members have reached their maximum limits for the number of active free
- plan projects within organizations where they are an administrator or owner:
-
-
- {membersExceededLimit.map((member, idx: number) => (
-
- {member.username || member.primary_email} (Limit: {member.free_project_limit} free
- projects)
-
- ))}
-
-
- These members will need to either delete, pause, or upgrade one or more of these
- projects before you're able to create a free project within this organization.
-
-
- Upgrade plan
-
- }
- />
- )
-}
diff --git a/apps/studio/components/interfaces/Organization/NewProject/index.ts b/apps/studio/components/interfaces/Organization/NewProject/index.ts
deleted file mode 100644
index a52ded23d6bcc..0000000000000
--- a/apps/studio/components/interfaces/Organization/NewProject/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export { default as NotOrganizationOwnerWarning } from './NotOrganizationOwnerWarning'
diff --git a/apps/studio/components/interfaces/ProjectCreation/AdvancedConfiguration.tsx b/apps/studio/components/interfaces/ProjectCreation/AdvancedConfiguration.tsx
index 9ed6663b7c91e..18b4d4c5eb025 100644
--- a/apps/studio/components/interfaces/ProjectCreation/AdvancedConfiguration.tsx
+++ b/apps/studio/components/interfaces/ProjectCreation/AdvancedConfiguration.tsx
@@ -4,7 +4,6 @@ import { UseFormReturn } from 'react-hook-form'
import { DocsButton } from 'components/ui/DocsButton'
import Panel from 'components/ui/Panel'
import { DOCS_URL } from 'lib/constants'
-import { CreateProjectForm } from 'pages/new/[slug]'
import {
Badge,
cn,
@@ -19,6 +18,7 @@ import {
} from 'ui'
import { Admonition } from 'ui-patterns'
import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
+import { CreateProjectForm } from './ProjectCreation.schema'
interface AdvancedConfigurationProps {
form: UseFormReturn
diff --git a/apps/studio/components/interfaces/ProjectCreation/CloudProviderSelector.tsx b/apps/studio/components/interfaces/ProjectCreation/CloudProviderSelector.tsx
new file mode 100644
index 0000000000000..92e6f70ea577b
--- /dev/null
+++ b/apps/studio/components/interfaces/ProjectCreation/CloudProviderSelector.tsx
@@ -0,0 +1,63 @@
+import { UseFormReturn } from 'react-hook-form'
+
+import Panel from 'components/ui/Panel'
+import { useCustomContent } from 'hooks/custom-content/useCustomContent'
+import { PROVIDERS } from 'lib/constants'
+import {
+ FormControl_Shadcn_,
+ FormField_Shadcn_,
+ Select_Shadcn_,
+ SelectContent_Shadcn_,
+ SelectGroup_Shadcn_,
+ SelectItem_Shadcn_,
+ SelectTrigger_Shadcn_,
+ SelectValue_Shadcn_,
+} from 'ui'
+import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
+import { CreateProjectForm } from './ProjectCreation.schema'
+
+interface CloudProviderSelectorProps {
+ form: UseFormReturn
+}
+
+export const CloudProviderSelector = ({ form }: CloudProviderSelectorProps) => {
+ const { infraCloudProviders: validCloudProviders } = useCustomContent(['infra:cloud_providers'])
+
+ return (
+
+ (
+
+ field.onChange(value)}
+ defaultValue={field.value}
+ >
+
+
+
+
+
+
+
+ {Object.values(PROVIDERS)
+ .filter((provider) => validCloudProviders?.includes(provider.id) ?? true)
+ .map((providerObj) => {
+ const label = providerObj['name']
+ const value = providerObj['id']
+ return (
+
+ {label}
+
+ )
+ })}
+
+
+
+
+ )}
+ />
+
+ )
+}
diff --git a/apps/studio/components/interfaces/ProjectCreation/ComputeSizeSelector.tsx b/apps/studio/components/interfaces/ProjectCreation/ComputeSizeSelector.tsx
new file mode 100644
index 0000000000000..8797c7619d461
--- /dev/null
+++ b/apps/studio/components/interfaces/ProjectCreation/ComputeSizeSelector.tsx
@@ -0,0 +1,122 @@
+import { UseFormReturn } from 'react-hook-form'
+
+import { InlineLink } from 'components/ui/InlineLink'
+import Panel from 'components/ui/Panel'
+import { instanceSizeSpecs } from 'data/projects/new-project.constants'
+import { getCloudProviderArchitecture } from 'lib/cloudprovider-utils'
+import { DOCS_URL } from 'lib/constants'
+import { CloudProvider } from 'shared-data'
+import {
+ Badge,
+ FormField_Shadcn_,
+ Select_Shadcn_,
+ SelectContent_Shadcn_,
+ SelectGroup_Shadcn_,
+ SelectItem_Shadcn_,
+ SelectTrigger_Shadcn_,
+ SelectValue_Shadcn_,
+} from 'ui'
+import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
+import { sizes } from './ProjectCreation.constants'
+import { CreateProjectForm } from './ProjectCreation.schema'
+
+interface ComputeSizeSelectorProps {
+ form: UseFormReturn
+}
+
+export const ComputeSizeSelector = ({ form }: ComputeSizeSelectorProps) => {
+ return (
+
+ (
+
+
+ The size for your dedicated database. You can change this later. Learn more about{' '}
+
+ compute add-ons
+ {' '}
+ and{' '}
+
+ compute billing
+
+ .
+
+ >
+ }
+ >
+ field.onChange(value)}>
+
+
+
+
+
+ {sizes
+ .filter((option) =>
+ instanceSizeSpecs[option].cloud_providers.includes(
+ form.getValues('cloudProvider') as CloudProvider
+ )
+ )
+ .map((option) => {
+ return (
+
+
+
+
+ {instanceSizeSpecs[option].label}
+
+
+
+
+ {instanceSizeSpecs[option].ram} RAM /{' '}
+ {instanceSizeSpecs[option].cpu}{' '}
+ {getCloudProviderArchitecture(
+ form.getValues('cloudProvider') as CloudProvider
+ )}{' '}
+ CPU
+
+
+ ${instanceSizeSpecs[option].priceHourly}/hour (~$
+ {instanceSizeSpecs[option].priceMonthly}/month)
+
+
+
+
+ )
+ })}
+
+
+ Larger instance sizes available after creation
+
+
+
+
+
+
+ )}
+ />
+
+ )
+}
diff --git a/apps/studio/components/interfaces/ProjectCreation/CustomPostgresVersionInput.tsx b/apps/studio/components/interfaces/ProjectCreation/CustomPostgresVersionInput.tsx
new file mode 100644
index 0000000000000..27e514e3dccd4
--- /dev/null
+++ b/apps/studio/components/interfaces/ProjectCreation/CustomPostgresVersionInput.tsx
@@ -0,0 +1,32 @@
+import { UseFormReturn } from 'react-hook-form'
+
+import Panel from 'components/ui/Panel'
+import { FormControl_Shadcn_, FormField_Shadcn_, Input_Shadcn_ } from 'ui'
+import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
+import { CreateProjectForm } from './ProjectCreation.schema'
+
+interface CustomPostgresVersionInputProps {
+ form: UseFormReturn
+}
+
+export const CustomPostgresVersionInput = ({ form }: CustomPostgresVersionInputProps) => {
+ return (
+
+ (
+
+
+
+
+
+ )}
+ />
+
+ )
+}
diff --git a/apps/studio/components/interfaces/ProjectCreation/DatabasePasswordInput.tsx b/apps/studio/components/interfaces/ProjectCreation/DatabasePasswordInput.tsx
new file mode 100644
index 0000000000000..2777920390239
--- /dev/null
+++ b/apps/studio/components/interfaces/ProjectCreation/DatabasePasswordInput.tsx
@@ -0,0 +1,102 @@
+import { debounce } from 'lodash'
+import { useRef } from 'react'
+import { UseFormReturn } from 'react-hook-form'
+
+import Panel from 'components/ui/Panel'
+import PasswordStrengthBar from 'components/ui/PasswordStrengthBar'
+import passwordStrength from 'lib/password-strength'
+import { generateStrongPassword } from 'lib/project'
+import { FormControl_Shadcn_, FormField_Shadcn_ } from 'ui'
+import { Input } from 'ui-patterns/DataInputs/Input'
+import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
+import { DATABASE_PASSWORD_REGEX } from './ProjectCreation.constants'
+import { CreateProjectForm } from './ProjectCreation.schema'
+import { SpecialSymbolsCallout } from './SpecialSymbolsCallout'
+
+interface DatabasePasswordInputProps {
+ form: UseFormReturn
+ passwordStrengthMessage: string
+ setPasswordStrengthMessage: (value: string) => void
+ setPasswordStrengthWarning: (value: string) => void
+}
+
+export const DatabasePasswordInput = ({
+ form,
+ passwordStrengthMessage,
+ setPasswordStrengthMessage,
+ setPasswordStrengthWarning,
+}: DatabasePasswordInputProps) => {
+ async function checkPasswordStrength(value: any) {
+ const { message, warning, strength } = await passwordStrength(value)
+
+ form.setValue('dbPassStrength', strength)
+ form.trigger('dbPassStrength')
+ form.trigger('dbPass')
+
+ setPasswordStrengthWarning(warning)
+ setPasswordStrengthMessage(message)
+ }
+
+ const delayedCheckPasswordStrength = useRef(
+ debounce((value) => checkPasswordStrength(value), 300)
+ ).current
+
+ // [Refactor] DB Password could be a common component used in multiple pages with repeated logic
+ function generatePassword() {
+ const password = generateStrongPassword()
+ form.setValue('dbPass', password)
+ delayedCheckPasswordStrength(password)
+ }
+
+ return (
+
+ {
+ const isInvalidDatabasePassword =
+ field.value.length > 0 && !field.value.match(DATABASE_PASSWORD_REGEX)
+
+ return (
+
+ {isInvalidDatabasePassword && }
+
+ >
+ }
+ >
+
+ 0}
+ type="password"
+ placeholder="Type in a strong password"
+ {...field}
+ autoComplete="off"
+ onChange={async (event) => {
+ field.onChange(event)
+ form.trigger('dbPassStrength')
+ const value = event.target.value
+ if (event.target.value === '') {
+ await form.setValue('dbPassStrength', 0)
+ await form.trigger('dbPass')
+ } else {
+ await delayedCheckPasswordStrength(value)
+ }
+ }}
+ />
+
+
+ )
+ }}
+ />
+
+ )
+}
diff --git a/apps/studio/components/interfaces/ProjectCreation/DisabledWarningDueToIncident.tsx b/apps/studio/components/interfaces/ProjectCreation/DisabledWarningDueToIncident.tsx
new file mode 100644
index 0000000000000..e18d5efb3ad2b
--- /dev/null
+++ b/apps/studio/components/interfaces/ProjectCreation/DisabledWarningDueToIncident.tsx
@@ -0,0 +1,31 @@
+import { AlertCircle } from 'lucide-react'
+
+import InformationBox from 'components/ui/InformationBox'
+import Panel from 'components/ui/Panel'
+
+interface DisabledWarningDueToIncidentProps {
+ title: string
+}
+
+export const DisabledWarningDueToIncident = ({ title }: DisabledWarningDueToIncidentProps) => {
+ return (
+
+ }
+ defaultVisibility={true}
+ hideCollapse
+ title={title}
+ description={
+
+ }
+ />
+
+ )
+}
diff --git a/apps/studio/components/interfaces/ProjectCreation/FreeProjectLimitWarning.tsx b/apps/studio/components/interfaces/ProjectCreation/FreeProjectLimitWarning.tsx
new file mode 100644
index 0000000000000..00b5e33da992f
--- /dev/null
+++ b/apps/studio/components/interfaces/ProjectCreation/FreeProjectLimitWarning.tsx
@@ -0,0 +1,41 @@
+import Panel from 'components/ui/Panel'
+import { UpgradePlanButton } from 'components/ui/UpgradePlanButton'
+import type { MemberWithFreeProjectLimit } from 'data/organizations/free-project-limit-check-query'
+import { Admonition } from 'ui-patterns/admonition'
+
+interface FreeProjectLimitWarningProps {
+ membersExceededLimit: MemberWithFreeProjectLimit[]
+}
+
+export const FreeProjectLimitWarning = ({ membersExceededLimit }: FreeProjectLimitWarningProps) => {
+ return (
+
+
+
+ The following members have reached their maximum limits for the number of active free
+ plan projects within organizations where they are an administrator or owner:
+
+
+ {membersExceededLimit.map((member, idx: number) => (
+
+ {member.username || member.primary_email} (Limit: {member.free_project_limit} free
+ projects)
+
+ ))}
+
+
+ These members will need to either delete, pause, or upgrade one or more of these
+ projects before you're able to create a free project within this organization.
+
+
+ Upgrade plan
+
+ }
+ />
+
+ )
+}
diff --git a/apps/studio/components/interfaces/Organization/NewProject/NotOrganizationOwnerWarning.tsx b/apps/studio/components/interfaces/ProjectCreation/NotOrganizationOwnerWarning.tsx
similarity index 88%
rename from apps/studio/components/interfaces/Organization/NewProject/NotOrganizationOwnerWarning.tsx
rename to apps/studio/components/interfaces/ProjectCreation/NotOrganizationOwnerWarning.tsx
index a74dcafae7411..c08d172ebae3d 100644
--- a/apps/studio/components/interfaces/Organization/NewProject/NotOrganizationOwnerWarning.tsx
+++ b/apps/studio/components/interfaces/ProjectCreation/NotOrganizationOwnerWarning.tsx
@@ -6,7 +6,7 @@ interface NotOrganizationOwnerWarningProps {
}
// [Joshen] This can just use NoPermission component i think
-const NotOrganizationOwnerWarning = ({ slug }: NotOrganizationOwnerWarningProps) => {
+export const NotOrganizationOwnerWarning = ({ slug }: NotOrganizationOwnerWarningProps) => {
return (
)
}
-
-export default NotOrganizationOwnerWarning
diff --git a/apps/studio/components/interfaces/ProjectCreation/OrganizationSelector.tsx b/apps/studio/components/interfaces/ProjectCreation/OrganizationSelector.tsx
new file mode 100644
index 0000000000000..39c8b32a8d82e
--- /dev/null
+++ b/apps/studio/components/interfaces/ProjectCreation/OrganizationSelector.tsx
@@ -0,0 +1,89 @@
+import { PermissionAction } from '@supabase/shared-types/out/constants'
+import { useRouter } from 'next/router'
+import { UseFormReturn } from 'react-hook-form'
+
+import { useParams } from 'common'
+import Panel from 'components/ui/Panel'
+import { useOrganizationsQuery } from 'data/organizations/organizations-query'
+import { useAsyncCheckPermissions } from 'hooks/misc/useCheckPermissions'
+import { useSelectedOrganizationQuery } from 'hooks/misc/useSelectedOrganization'
+import {
+ Badge,
+ FormControl_Shadcn_,
+ FormField_Shadcn_,
+ Select_Shadcn_,
+ SelectContent_Shadcn_,
+ SelectGroup_Shadcn_,
+ SelectItem_Shadcn_,
+ SelectTrigger_Shadcn_,
+ SelectValue_Shadcn_,
+} from 'ui'
+import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
+import { OrgNotFound } from '../Organization/OrgNotFound'
+import { NotOrganizationOwnerWarning } from './NotOrganizationOwnerWarning'
+import { CreateProjectForm } from './ProjectCreation.schema'
+
+interface OrganizationSelectorProps {
+ form: UseFormReturn
+}
+
+export const OrganizationSelector = ({ form }: OrganizationSelectorProps) => {
+ const router = useRouter()
+ const { slug } = useParams()
+ const { data: currentOrg } = useSelectedOrganizationQuery()
+ const { can: isAdmin } = useAsyncCheckPermissions(PermissionAction.CREATE, 'projects')
+
+ const { data: organizations, isSuccess: isOrganizationsSuccess } = useOrganizationsQuery()
+ const isInvalidSlug = isOrganizationsSuccess && currentOrg === undefined
+ const orgNotFound = (organizations?.length ?? 0) > 0 && isInvalidSlug
+
+ return (
+
+ {isAdmin && !isInvalidSlug && (
+ (
+
+ {(organizations?.length ?? 0) > 0 && (
+ {
+ field.onChange(slug)
+ router.push(`/new/${slug}`)
+ }}
+ value={field.value}
+ defaultValue={field.value}
+ >
+
+
+
+
+
+
+
+ {organizations?.map((x) => (
+
+ {x.name}
+ {x.plan.name}
+
+ ))}
+
+
+
+ )}
+
+ )}
+ />
+ )}
+
+ {isOrganizationsSuccess && !isAdmin && !orgNotFound && (
+
+ )}
+ {orgNotFound && }
+
+ )
+}
diff --git a/apps/studio/components/interfaces/ProjectCreation/ProjectCreation.constants.ts b/apps/studio/components/interfaces/ProjectCreation/ProjectCreation.constants.ts
index 323ee0082d6ca..75ef67137abb8 100644
--- a/apps/studio/components/interfaces/ProjectCreation/ProjectCreation.constants.ts
+++ b/apps/studio/components/interfaces/ProjectCreation/ProjectCreation.constants.ts
@@ -1,3 +1,5 @@
+import { DesiredInstanceSize } from 'data/projects/new-project.constants'
+
// [Joshen] Obtained from https://gist.github.com/tadast/8827699
export const COUNTRY_LAT_LON = {
AF: { lat: 33, lon: 65 },
@@ -253,4 +255,6 @@ export const COUNTRY_LAT_LON = {
ZW: { lat: -20, lon: 30 },
}
-export const SPECIAL_CHARS_REGEX = /^[^@:\/]*$/
+export const DATABASE_PASSWORD_REGEX = /^[^@:\/]*$/
+
+export const sizes: DesiredInstanceSize[] = ['micro', 'small', 'medium']
diff --git a/apps/studio/components/interfaces/ProjectCreation/ProjectCreation.schema.ts b/apps/studio/components/interfaces/ProjectCreation/ProjectCreation.schema.ts
new file mode 100644
index 0000000000000..334050a692813
--- /dev/null
+++ b/apps/studio/components/interfaces/ProjectCreation/ProjectCreation.schema.ts
@@ -0,0 +1,33 @@
+import { z } from 'zod'
+
+export const FormSchema = z.object({
+ organization: z.string({
+ required_error: 'Please select an organization',
+ }),
+ projectName: z
+ .string()
+ .trim()
+ .min(1, 'Please enter a project name.') // Required field check
+ .min(3, 'Project name must be at least 3 characters long.') // Minimum length check
+ .max(64, 'Project name must be no longer than 64 characters.'), // Maximum length check
+ postgresVersion: z.string({
+ required_error: 'Please enter a Postgres version.',
+ }),
+ dbRegion: z.string({
+ required_error: 'Please select a region.',
+ }),
+ cloudProvider: z.string({
+ required_error: 'Please select a cloud provider.',
+ }),
+ dbPassStrength: z.number(),
+ dbPass: z
+ .string({ required_error: 'Please enter a database password.' })
+ .min(1, 'Password is required.'),
+ instanceSize: z.string().optional(),
+ dataApi: z.boolean(),
+ useApiSchema: z.boolean(),
+ postgresVersionSelection: z.string(),
+ useOrioleDb: z.boolean(),
+})
+
+export type CreateProjectForm = z.infer
diff --git a/apps/studio/components/interfaces/ProjectCreation/ProjectCreation.test.ts b/apps/studio/components/interfaces/ProjectCreation/ProjectCreation.test.ts
index 289c047560469..6c8c546b97128 100644
--- a/apps/studio/components/interfaces/ProjectCreation/ProjectCreation.test.ts
+++ b/apps/studio/components/interfaces/ProjectCreation/ProjectCreation.test.ts
@@ -1,10 +1,10 @@
import { expect, test } from 'vitest'
-import { SPECIAL_CHARS_REGEX } from './ProjectCreation.constants'
+import { DATABASE_PASSWORD_REGEX } from './ProjectCreation.constants'
test('Regex test to surface if password contains @, : or /', () => {
- expect(!'teststring'.match(SPECIAL_CHARS_REGEX)).toEqual(false)
- expect(!'test@string'.match(SPECIAL_CHARS_REGEX)).toEqual(true)
- expect(!'te:ststring'.match(SPECIAL_CHARS_REGEX)).toEqual(true)
- expect(!`tests/tring`.match(SPECIAL_CHARS_REGEX)).toEqual(true)
- expect(!'!#$%^&*()'.match(SPECIAL_CHARS_REGEX)).toEqual(false)
+ expect(!'teststring'.match(DATABASE_PASSWORD_REGEX)).toEqual(false)
+ expect(!'test@string'.match(DATABASE_PASSWORD_REGEX)).toEqual(true)
+ expect(!'te:ststring'.match(DATABASE_PASSWORD_REGEX)).toEqual(true)
+ expect(!`tests/tring`.match(DATABASE_PASSWORD_REGEX)).toEqual(true)
+ expect(!'!#$%^&*()'.match(DATABASE_PASSWORD_REGEX)).toEqual(false)
})
diff --git a/apps/studio/components/interfaces/ProjectCreation/ProjectCreation.utils.ts b/apps/studio/components/interfaces/ProjectCreation/ProjectCreation.utils.ts
index 2db5478777f72..142542f318cc5 100644
--- a/apps/studio/components/interfaces/ProjectCreation/ProjectCreation.utils.ts
+++ b/apps/studio/components/interfaces/ProjectCreation/ProjectCreation.utils.ts
@@ -1,3 +1,4 @@
+import { DesiredInstanceSize, instanceSizeSpecs } from 'data/projects/new-project.constants'
import type { CloudProvider, Region } from 'shared-data'
import { AWS_REGIONS, FLY_REGIONS } from 'shared-data'
import { SMART_REGION_TO_EXACT_REGION_MAP } from 'shared-data/regions'
@@ -29,3 +30,17 @@ export function getAvailableRegions(cloudProvider: CloudProvider): Region {
throw new Error('Invalid cloud provider')
}
}
+
+/**
+ * When launching new projects, they only get assigned a compute size once successfully launched,
+ * this might assume wrong compute size, but only for projects being rapidly launched after one another on non-default compute sizes.
+ *
+ * Needs to be in the API in the future [kevin]
+ */
+export const monthlyInstancePrice = (instance: string | undefined): number => {
+ return instanceSizeSpecs[instance as DesiredInstanceSize]?.priceMonthly || 10
+}
+
+export const instanceLabel = (instance: string | undefined): string => {
+ return instanceSizeSpecs[instance as DesiredInstanceSize]?.label || 'Micro'
+}
diff --git a/apps/studio/components/interfaces/ProjectCreation/ProjectCreationFooter.tsx b/apps/studio/components/interfaces/ProjectCreation/ProjectCreationFooter.tsx
new file mode 100644
index 0000000000000..c64dd7795a5cb
--- /dev/null
+++ b/apps/studio/components/interfaces/ProjectCreation/ProjectCreationFooter.tsx
@@ -0,0 +1,197 @@
+import { useRouter } from 'next/router'
+import { UseFormReturn } from 'react-hook-form'
+
+import { LOCAL_STORAGE_KEYS, useFlag } from 'common'
+import { InlineLink } from 'components/ui/InlineLink'
+import { DesiredInstanceSize, instanceSizeSpecs } from 'data/projects/new-project.constants'
+import { OrgProject } from 'data/projects/org-projects-infinite-query'
+import { useLocalStorageQuery } from 'hooks/misc/useLocalStorage'
+import { useSelectedOrganizationQuery } from 'hooks/misc/useSelectedOrganization'
+import { DOCS_URL } from 'lib/constants'
+import {
+ Badge,
+ Button,
+ PopoverSeparator_Shadcn_,
+ Table,
+ TableBody,
+ TableCell,
+ TableHead,
+ TableHeader,
+ TableRow,
+} from 'ui'
+import { InfoTooltip } from 'ui-patterns/info-tooltip'
+import { CreateProjectForm } from './ProjectCreation.schema'
+import { instanceLabel, monthlyInstancePrice } from './ProjectCreation.utils'
+
+interface ProjectCreationFooterProps {
+ form: UseFormReturn
+ canCreateProject: boolean
+ instanceSize?: string
+ organizationProjects: OrgProject[]
+ isCreatingNewProject: boolean
+ isSuccessNewProject: boolean
+}
+
+export const ProjectCreationFooter = ({
+ form,
+ canCreateProject,
+ instanceSize,
+ organizationProjects,
+ isCreatingNewProject,
+ isSuccessNewProject,
+}: ProjectCreationFooterProps) => {
+ const router = useRouter()
+ const { data: currentOrg } = useSelectedOrganizationQuery()
+ const isFreePlan = currentOrg?.plan?.id === 'free'
+
+ const projectCreationDisabled = useFlag('disableProjectCreationAndUpdate')
+
+ const [lastVisitedOrganization] = useLocalStorageQuery(
+ LOCAL_STORAGE_KEYS.LAST_VISITED_ORGANIZATION,
+ ''
+ )
+
+ const availableComputeCredits = organizationProjects.length === 0 ? 10 : 0
+ const additionalMonthlySpend = isFreePlan
+ ? 0
+ : instanceSizeSpecs[instanceSize as DesiredInstanceSize]!.priceMonthly - availableComputeCredits
+
+ // [kevin] This will eventually all be provided by a new API endpoint to preview and validate project creation, this is just for kaizen now
+ const monthlyComputeCosts =
+ // current project costs
+ organizationProjects.reduce((prev, acc) => {
+ const primaryDatabase = acc.databases.find((db) => db.identifier === acc.ref)
+ const cost = !!primaryDatabase ? monthlyInstancePrice(primaryDatabase.infra_compute_size) : 0
+ return prev + cost
+ }, 0) +
+ // selected compute size
+ monthlyInstancePrice(instanceSize) -
+ // compute credits
+ 10
+
+ return (
+
+
+ {!isFreePlan &&
+ !projectCreationDisabled &&
+ canCreateProject &&
+ additionalMonthlySpend > 0 && (
+
+
Additional costs
+
+
${additionalMonthlySpend}/m
+
+
+
+ Each project includes a dedicated Postgres instance running on its own server.
+ You are charged for the{' '}
+
+ Compute resource
+ {' '}
+ of that server, independent of your database usage.
+
+ {monthlyComputeCosts > 0 && (
+
Compute costs are applied on top of your subscription plan costs.
+ )}
+
+
+
+
+
+ Project
+ Compute Size
+ Monthly Costs
+
+
+
+ {organizationProjects.map((project) => {
+ const primaryDb = project.databases.find(
+ (db) => db.identifier === project.ref
+ )
+ return (
+
+ {project.name}
+
+ {instanceLabel(primaryDb?.infra_compute_size)}
+
+
+ ${monthlyInstancePrice(primaryDb?.infra_compute_size)}
+
+
+ )
+ })}
+
+
+
+
+ {form.getValues('projectName') ?? 'New project'}
+
+
+ NEW
+
+
+ {instanceLabel(instanceSize)}
+
+ ${monthlyInstancePrice(instanceSize)}
+
+
+
+
+
+
+
+
+ Compute Credits
+
+ -$10
+
+
+
+
+
+
+ Total Monthly Compute Costs
+ {/**
+ * API currently doesnt output replica information on the projects list endpoint. Until then, we cannot correctly calculate the costs including RRs.
+ * Will be adjusted in the future [kevin]
+ */}
+ {organizationProjects.length > 0 && (
+
+ Excluding Read replicas
+
+ )}
+
+
+ ${monthlyComputeCosts}
+
+
+
+
+
+
+
+ )}
+
+
+
+ {
+ if (!!lastVisitedOrganization) router.push(`/org/${lastVisitedOrganization}`)
+ else router.push('/organizations')
+ }}
+ >
+ Cancel
+
+
+ Create new project
+
+
+
+ )
+}
diff --git a/apps/studio/components/interfaces/ProjectCreation/ProjectNameInput.tsx b/apps/studio/components/interfaces/ProjectCreation/ProjectNameInput.tsx
new file mode 100644
index 0000000000000..9d3be73eb22db
--- /dev/null
+++ b/apps/studio/components/interfaces/ProjectCreation/ProjectNameInput.tsx
@@ -0,0 +1,28 @@
+import { UseFormReturn } from 'react-hook-form'
+
+import Panel from 'components/ui/Panel'
+import { FormControl_Shadcn_, FormField_Shadcn_, Input_Shadcn_ } from 'ui'
+import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
+import { CreateProjectForm } from './ProjectCreation.schema'
+
+interface ProjectNameInputProps {
+ form: UseFormReturn
+}
+
+export const ProjectNameInput = ({ form }: ProjectNameInputProps) => {
+ return (
+
+ (
+
+
+
+
+
+ )}
+ />
+
+ )
+}
diff --git a/apps/studio/components/interfaces/ProjectCreation/RegionSelector.tsx b/apps/studio/components/interfaces/ProjectCreation/RegionSelector.tsx
index 7630a524b0be0..d7578686bc49c 100644
--- a/apps/studio/components/interfaces/ProjectCreation/RegionSelector.tsx
+++ b/apps/studio/components/interfaces/ProjectCreation/RegionSelector.tsx
@@ -1,7 +1,8 @@
-import { ControllerRenderProps } from 'react-hook-form'
+import { UseFormReturn } from 'react-hook-form'
import { useFlag, useParams } from 'common'
import AlertError from 'components/ui/AlertError'
+import Panel from 'components/ui/Panel'
import { useDefaultRegionQuery } from 'data/misc/get-default-region-query'
import { useOrganizationAvailableRegionsQuery } from 'data/organizations/organization-available-regions-query'
import type { DesiredInstanceSize } from 'data/projects/new-project.constants'
@@ -9,6 +10,7 @@ import { BASE_PATH, PROVIDERS } from 'lib/constants'
import type { CloudProvider } from 'shared-data'
import {
Badge,
+ FormField_Shadcn_,
SelectContent_Shadcn_,
SelectGroup_Shadcn_,
SelectItem_Shadcn_,
@@ -23,11 +25,11 @@ import {
cn,
} from 'ui'
import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
+import { CreateProjectForm } from './ProjectCreation.schema'
import { getAvailableRegions } from './ProjectCreation.utils'
interface RegionSelectorProps {
- cloudProvider: CloudProvider
- field: ControllerRenderProps
+ form: UseFormReturn
instanceSize?: DesiredInstanceSize
layout?: 'vertical' | 'horizontal'
}
@@ -37,12 +39,12 @@ interface RegionSelectorProps {
// ^ can try again next time
export const RegionSelector = ({
- cloudProvider,
- field,
+ form,
instanceSize,
layout = 'horizontal',
}: RegionSelectorProps) => {
const { slug } = useParams()
+ const cloudProvider = form.getValues('cloudProvider') as CloudProvider
const smartRegionEnabled = useFlag('enableSmartRegion')
@@ -89,145 +91,164 @@ export const RegionSelector = ({
process.env.NEXT_PUBLIC_ENVIRONMENT === 'staging'
const allSelectableRegions = [...smartRegions, ...regionOptions]
- const selectedRegion = allSelectableRegions.find((region) => {
- return !!region.name && region.name === field.value
- })
if (isErrorAvailableRegions) {
return
}
return (
-
- Select the region closest to your users for the best performance.
- {showNonProdFields && (
-
-
Only these regions are supported for local/staging projects:
-
- East US (North Virginia)
- Central EU (Frankfurt)
- Southeast Asia (Singapore)
-
-
- )}
- >
- }
- >
-
-
-
- {field.value !== undefined && (
-
- {selectedRegion?.code && (
-
- )}
-
{selectedRegion?.name ?? field.value}
-
- )}
-
-
-
- {smartRegionEnabled && (
- <>
-
- Smart Region Selection
- {smartRegions.map((value) => {
- return (
-
-
-
+
+ {
+ const selectedRegion = allSelectableRegions.find((region) => {
+ return !!region.name && region.name === field.value
+ })
+
+ return (
+
+ Select the region closest to your users for the best performance.
+ {showNonProdFields && (
+
+
Only these regions are supported for local/staging projects:
+
+ East US (North Virginia)
+ Central EU (Frankfurt)
+ Southeast Asia (Singapore)
+
+
+ )}
+ >
+ }
+ >
+
+
+
+ {field.value !== undefined && (
+
+ {selectedRegion?.code && (
-
{value.name}
-
-
-
- {recommendedSmartRegions.has(value.code) && (
-
- Recommended
-
- )}
-
-
-
- )
- })}
-
-
- >
- )}
-
-
- All Regions
- {regionOptions.map((value) => {
- return (
- :nth-child(2)]:w-full',
- value.status !== undefined && '!pointer-events-auto'
- )}
- disabled={value.status !== undefined}
- >
-
-
-
-
- {value.name}
-
- {value.code}
+ )}
+
+ {selectedRegion?.name ?? field.value}
-
-
- {recommendedSpecificRegions.has(value.code) && (
-
- Recommended
-
- )}
- {value.status !== undefined && value.status === 'capacity' && (
-
-
-
- Unavailable
-
-
-
- Temporarily unavailable due to this region being at capacity.
-
-
)}
-
-
- )
- })}
-
-
-
-
+
+
+
+ {smartRegionEnabled && (
+ <>
+
+ Smart Region Selection
+ {smartRegions.map((value) => {
+ return (
+
+
+
+
+
{value.name}
+
+
+
+ {recommendedSmartRegions.has(value.code) && (
+
+ Recommended
+
+ )}
+
+
+
+ )
+ })}
+
+
+ >
+ )}
+
+
+ All Regions
+ {regionOptions.map((value) => {
+ return (
+ :nth-child(2)]:w-full',
+ value.status !== undefined && '!pointer-events-auto'
+ )}
+ disabled={value.status !== undefined}
+ >
+
+
+
+
+ {value.name}
+
+ {value.code}
+
+
+
+
+ {recommendedSpecificRegions.has(value.code) && (
+
+ Recommended
+
+ )}
+ {value.status !== undefined && value.status === 'capacity' && (
+
+
+
+ Unavailable
+
+
+
+ Temporarily unavailable due to this region being at capacity.
+
+
+ )}
+
+
+ )
+ })}
+
+
+
+
+ )
+ }}
+ />
+
)
}
diff --git a/apps/studio/components/interfaces/ProjectCreation/SecurityOptions.tsx b/apps/studio/components/interfaces/ProjectCreation/SecurityOptions.tsx
index 7e13206a3a501..69fd74fed258e 100644
--- a/apps/studio/components/interfaces/ProjectCreation/SecurityOptions.tsx
+++ b/apps/studio/components/interfaces/ProjectCreation/SecurityOptions.tsx
@@ -2,7 +2,6 @@ import { ChevronRight } from 'lucide-react'
import { UseFormReturn } from 'react-hook-form'
import Panel from 'components/ui/Panel'
-import { CreateProjectForm } from 'pages/new/[slug]'
import {
Badge,
cn,
@@ -17,6 +16,7 @@ import {
} from 'ui'
import { Admonition } from 'ui-patterns'
import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
+import { CreateProjectForm } from './ProjectCreation.schema'
interface SecurityOptionsProps {
form: UseFormReturn
diff --git a/apps/studio/components/interfaces/Realtime/RealtimeSettings.tsx b/apps/studio/components/interfaces/Realtime/RealtimeSettings.tsx
index eb3d18eaa5220..13a8ec32d22d9 100644
--- a/apps/studio/components/interfaces/Realtime/RealtimeSettings.tsx
+++ b/apps/studio/components/interfaces/Realtime/RealtimeSettings.tsx
@@ -1,6 +1,5 @@
import { zodResolver } from '@hookform/resolvers/zod'
import { PermissionAction } from '@supabase/shared-types/out/constants'
-import Link from 'next/link'
import { useState } from 'react'
import { SubmitHandler, useForm } from 'react-hook-form'
import { toast } from 'sonner'
@@ -22,6 +21,7 @@ import {
import { useAsyncCheckPermissions } from 'hooks/misc/useCheckPermissions'
import { useSelectedOrganizationQuery } from 'hooks/misc/useSelectedOrganization'
import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
+import Link from 'next/link'
import {
Button,
Card,
@@ -68,7 +68,7 @@ export const RealtimeSettings = () => {
const isFreePlan = organization?.plan.id === 'free'
const isUsageBillingEnabled = organization?.usage_billing_enabled
- const isRealtimeDisabed = data?.suspend ?? REALTIME_DEFAULT_CONFIG.suspend
+ const isRealtimeDisabled = data?.suspend ?? REALTIME_DEFAULT_CONFIG.suspend
// Check if RLS policies exist for realtime.messages table
const realtimeMessagesPolicies = policies?.filter(
(policy) => policy.schema === 'realtime' && policy.table === 'messages'
@@ -115,8 +115,10 @@ export const RealtimeSettings = () => {
} as any,
})
- const { allow_public } = form.watch()
+ const { allow_public, suspend } = form.watch()
const isSettingToPrivate = !data?.private_only && !allow_public
+ const isDisablingRealtime = !isRealtimeDisabled && suspend
+ const isEnablingRealtime = isRealtimeDisabled && !suspend
const onSubmit: SubmitHandler> = (data) => {
if (!projectRef) return console.error('Project ref is required')
@@ -167,7 +169,7 @@ export const RealtimeSettings = () => {
{
- {isSuccessOrganization && isRealtimeDisabed && (
-
+ {(isRealtimeDisabled || isDisablingRealtime || isEnablingRealtime) && (
+
- Realtime service is disabled
+ {isDisablingRealtime
+ ? 'Realtime service will be disabled'
+ : isEnablingRealtime
+ ? 'Realtime service will be re-enabled'
+ : isRealtimeDisabled
+ ? 'Realtime service is disabled'
+ : null}
- You will need to enable it to continue using Realtime
+ {isDisablingRealtime
+ ? 'Clients will no longer be able to connect to your project’s realtime service once saved'
+ : isEnablingRealtime
+ ? "Clients will be able to connect to your project's realtime service again once saved"
+ : isRealtimeDisabled
+ ? 'You will need to enable it to continue using Realtime'
+ : null}
@@ -197,450 +216,342 @@ export const RealtimeSettings = () => {
)}
/>
-
- (
- Channel restrictions}
- >
-
-
+
+ (
+ Channel restrictions}
>
-
-
-
-
+
+
+
+
+
+
- {isSuccessPolicies &&
- !hasRealtimeMessagesPolicies &&
- !allow_public &&
- !isRealtimeDisabed && (
-
-
- Private mode is {isSettingToPrivate ? 'being ' : ''}
- enabled, but no RLS policies exists on the{' '}
- realtime.messages table. No
- messages will be received by users.
-
+ {isSuccessPolicies &&
+ !hasRealtimeMessagesPolicies &&
+ !allow_public &&
+ !isRealtimeDisabled && (
+
+
+ Private mode is {isSettingToPrivate ? 'being ' : ''}
+ enabled, but no RLS policies exists on the{' '}
+ realtime.messages table.
+ No messages will be received by users.
+
-
-
- Create policy
-
-
- >
+
+
+ Create policy
+
+
+ >
+ }
+ />
+ )}
+
+
+ )}
+ />
+
+
+ (
+
+ Realtime Authorization uses this database pool to check client
+ access
+
}
- />
- )}
-
-
- )}
- />
-
-
- (
-
- Realtime Authorization uses this database pool to check client
- access
-
+ >
+ Database connection pool size
+
}
>
- Database connection pool size
-
- }
- >
-
-
-
-
-
- {!!maxConn && field.value > maxConn.maxConnections * 0.5 && (
-
- )}
-
-
- )}
- />
-
-
- (
-
- Sets maximum number of concurrent clients that can connect to your
- Realtime service
-
+
+
+
+
+
+ {!!maxConn && field.value > maxConn.maxConnections * 0.5 && (
+
+ )}
+
+
+ )}
+ />
+
+
+ (
+
+ Sets maximum number of concurrent clients that can connect to
+ your Realtime service
+
+ }
+ >
+ Max concurrent clients
+
}
>
- Max concurrent clients
-
- }
- >
-
-
-
-
-
-
-
- )}
- />
-
-
- (
-
- Sets maximum number of events per second that can be sent to your
- Realtime service
-
+
+
+
+
+
+
+
+ )}
+ />
+
+
+ (
+
+ Sets maximum number of events per second that can be sent to
+ your Realtime service
+
+ }
+ >
+ Max events per second
+
}
>
- Max events per second
-
- }
- >
-
-
-
-
-
- {isSuccessOrganization &&
- !isUsageBillingEnabled &&
- !isRealtimeDisabed && (
-
-
-
-
- Spend cap needs to be disabled to configure this value
-
-
- {isFreePlan
- ? 'Upgrade to the Pro plan first to disable spend cap'
- : 'You may adjust this setting in the organization billing settings'}
-
+
+
+
+
+
+ {isSuccessOrganization && !isUsageBillingEnabled && (
+
+
+
+
+ Spend cap needs to be disabled to configure this value
+
+
+ {isFreePlan
+ ? 'Upgrade to the Pro plan first to disable spend cap'
+ : 'You may adjust this setting in the organization billing settings'}
+
+
+
+ {isFreePlan ? (
+
+ ) : (
+
+ )}
+
-
- {isFreePlan ? (
-
- ) : (
-
- )}
-
-
-
- )}
-
-
- )}
- />
-
-
- (
-
- Sets maximum number of presence events per second that can be sent
- to your Realtime service
-
+
+ )}
+
+
+ )}
+ />
+
+
+ (
+
+ Sets maximum number of presence events per second that can be
+ sent to your Realtime service
+
+ }
+ >
+ Max presence events per second
+
}
>
- Max presence events per second
-
- }
- >
-
-
-
-
-
- {isSuccessOrganization &&
- !isUsageBillingEnabled &&
- !isRealtimeDisabed && (
-
-
-
-
- Spend cap needs to be disabled to configure this value
-
-
- {isFreePlan
- ? 'Upgrade to the Pro plan first to disable spend cap'
- : 'You may adjust this setting in the organization billing settings'}
-
+
+
+
+
+
+ {isSuccessOrganization && !isUsageBillingEnabled && (
+
+
+
+
+ Spend cap needs to be disabled to configure this value
+
+
+ {isFreePlan
+ ? 'Upgrade to the Pro plan first to disable spend cap'
+ : 'You may adjust this setting in the organization billing settings'}
+
+
+
+ {isFreePlan ? (
+
+ ) : (
+
+ )}
+
-
- {isFreePlan ? (
-
- ) : (
-
- )}
-
-
-
- )}
-
-
- )}
- />
-
-
- (
-
- Sets maximum number of payload size in KB that can be sent to your
- Realtime service
-
+
+ )}
+
+
+ )}
+ />
+
+
+ (
+
+ Sets maximum number of payload size in KB that can be sent to
+ your Realtime service
+
+ }
+ >
+ Max payload size in KB
+
}
>
- Max payload size in KB
-
- }
- >
-
-
-
-
-
- {isSuccessOrganization &&
- !isUsageBillingEnabled &&
- !isRealtimeDisabed && (
-
-
-
-
- Spend cap needs to be disabled to configure this value
-
-
- {isFreePlan
- ? 'Upgrade to the Pro plan first to disable spend cap'
- : 'You may adjust this setting in the organization billing settings'}
-
+
+
+
+
+
+ {isSuccessOrganization && !isUsageBillingEnabled && (
+
+
+
+
+ Spend cap needs to be disabled to configure this value
+
+
+ {isFreePlan
+ ? 'Upgrade to the Pro plan first to disable spend cap'
+ : 'You may adjust this setting in the organization billing settings'}
+
+
+
+ {isFreePlan ? (
+
+ ) : (
+
+ )}
+
-
- {isFreePlan ? (
-
- ) : (
-
- )}
-
-
-
- )}
-
-
- )}
- />
-
-
- {/*
- [Joshen] The following fields are hidden from the UI temporarily while we figure out what settings to expose to the users
- - Max bytes per second
- - Max channels per client
- - Max joins per second
- */}
-
- {/*
- {
- const { value, unit } = convertFromBytes(field.value ?? 0)
- return (
-
- Sets maximum number of bytes per second rate per channel limit
-
- }
- >
- Max bytes per second
-
- }
- >
-
-
-
-
-
- {!!field.value ? (
-
- This is equivalent to {value.toFixed(2)} {unit}
-
- ) : null}
-
-
- )
- }}
- />
- */}
- {/*
- (
-
- Sets maximum number of channels per client rate limit
-
- }
- >
- Max channels per client
-
- }
- >
-
-
-
-
-
-
-
- )}
- />
- */}
- {/*
- (
-
- Sets maximum number of joins per second rate limit
-
- }
- >
- Max joins per second
-
- }
- >
-
-
-
-
-
-
-
- )}
- />
- */}
+
+ )}
+
+
+ )}
+ />
+
+ >
+ )}
diff --git a/apps/studio/components/interfaces/Reports/v2/ReportChartV2.tsx b/apps/studio/components/interfaces/Reports/v2/ReportChartV2.tsx
index b84e320db062f..769ee3b4bacba 100644
--- a/apps/studio/components/interfaces/Reports/v2/ReportChartV2.tsx
+++ b/apps/studio/components/interfaces/Reports/v2/ReportChartV2.tsx
@@ -78,22 +78,20 @@ export const ReportChartV2 = ({
isLoading: isLoadingChart,
error,
isFetching,
- } = useQuery(
- [
+ } = useQuery({
+ queryKey: [
'projects',
projectRef,
'report-v2',
{ reportId: report.id, startDate, endDate, interval, filters },
],
- async () => {
+ queryFn: async () => {
return await report.dataProvider(projectRef, startDate, endDate, interval, filters)
},
- {
- enabled: Boolean(projectRef && canFetch && isAvailable && !report.hide),
- refetchOnWindowFocus: false,
- staleTime: 0,
- }
- )
+ enabled: Boolean(projectRef && canFetch && isAvailable && !report.hide),
+ refetchOnWindowFocus: false,
+ staleTime: 0,
+ })
const chartData = queryResult?.data || []
const dynamicAttributes = queryResult?.attributes || []
diff --git a/apps/studio/components/interfaces/Settings/General/General.tsx b/apps/studio/components/interfaces/Settings/General/General.tsx
index 61c0f7d22364a..fb8b87e4d5407 100644
--- a/apps/studio/components/interfaces/Settings/General/General.tsx
+++ b/apps/studio/components/interfaces/Settings/General/General.tsx
@@ -1,6 +1,7 @@
import { PermissionAction } from '@supabase/shared-types/out/constants'
import { BarChart2 } from 'lucide-react'
import Link from 'next/link'
+import { useState } from 'react'
import { toast } from 'sonner'
import { FormActions } from 'components/ui/Forms/FormActions'
@@ -30,6 +31,9 @@ const General = () => {
const { data: project } = useSelectedProjectQuery()
const { data: organization } = useSelectedOrganizationQuery()
+ // [Joshen] Need to refactor to use RHF so we don't need manual error handlers like this
+ const [nameError, setNameError] = useState
()
+
const { data: parentProject } = useProjectDetailQuery({ ref: project?.parent_project_ref })
const isBranch = parentProject !== undefined
@@ -50,6 +54,11 @@ const General = () => {
const onSubmit = async (values: any, { resetForm }: any) => {
if (!project?.ref) return console.error('Ref is required')
+ if (values.name.length < 3) {
+ setNameError('Project name must be at least 3 characters long')
+ return
+ }
+
updateProject(
{ ref: project.ref, name: values.name.trim() },
{
@@ -95,7 +104,10 @@ const General = () => {
form={formId}
isSubmitting={isUpdating}
hasChanges={hasChanges}
- handleReset={handleReset}
+ handleReset={() => {
+ handleReset()
+ setNameError(undefined)
+ }}
helper={
!canUpdateProject
? "You need additional permissions to manage this project's settings"
@@ -112,6 +124,8 @@ const General = () => {
size="small"
label="Project name"
disabled={isBranch || !canUpdateProject}
+ onChange={() => setNameError(undefined)}
+ error={nameError}
/>
diff --git a/apps/studio/components/interfaces/Storage/StorageMenu.BucketList.tsx b/apps/studio/components/interfaces/Storage/StorageMenu.BucketList.tsx
index b49c691a71f6b..c2d0193ce3d97 100644
--- a/apps/studio/components/interfaces/Storage/StorageMenu.BucketList.tsx
+++ b/apps/studio/components/interfaces/Storage/StorageMenu.BucketList.tsx
@@ -4,6 +4,7 @@ import type { ListChildComponentProps } from 'react-window'
import { FixedSizeList as List, areEqual } from 'react-window'
import type { Bucket } from 'data/storage/buckets-query'
+import { cn } from 'ui'
import { BucketRow } from './BucketRow'
type BucketListProps = {
@@ -25,7 +26,7 @@ const VirtualizedBucketRow = memo(
isSelected={isSelected}
projectRef={data.projectRef}
style={style as CSSProperties}
- className={BUCKET_ROW_HEIGHT}
+ className={cn(BUCKET_ROW_HEIGHT)}
/>
)
},
@@ -95,19 +96,15 @@ export const BucketList = ({ buckets, selectedBucketId, projectRef = '' }: Bucke
const numBuckets = buckets.length
if (numBuckets <= 50) {
- return (
-
- {buckets.map((bucket) => (
-
- ))}
-
- )
+ return buckets.map((bucket) => (
+
+ ))
}
return (
diff --git a/apps/studio/components/interfaces/Storage/StorageMenu.tsx b/apps/studio/components/interfaces/Storage/StorageMenu.tsx
index 8ffd4ca64e6c8..0ee63944eb88e 100644
--- a/apps/studio/components/interfaces/Storage/StorageMenu.tsx
+++ b/apps/studio/components/interfaces/Storage/StorageMenu.tsx
@@ -10,7 +10,7 @@ import { useBucketsQuery } from 'data/storage/buckets-query'
import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
import { IS_PLATFORM } from 'lib/constants'
import { useStorageExplorerStateSnapshot } from 'state/storage-explorer'
-import { Alert_Shadcn_, AlertDescription_Shadcn_, AlertTitle_Shadcn_, Menu } from 'ui'
+import { Alert_Shadcn_, AlertDescription_Shadcn_, AlertTitle_Shadcn_, cn, Menu } from 'ui'
import { InfoTooltip } from 'ui-patterns/info-tooltip'
import {
InnerSideBarEmptyPanel,
@@ -70,15 +70,12 @@ export const StorageMenu = () => {
[sortedBuckets, searchText]
)
const tempNotSupported = error?.message.includes('Tenant config') && isBranch
+ const isVirtualized = buckets.length > 50
return (
<>
-
-
+
+
@@ -110,8 +107,17 @@ export const StorageMenu = () => {
-
-
+
+
0
+ ? 'mb-3'
+ : 'mb-5'
+ )}
+ >
All buckets} />
{isLoading && (
@@ -165,27 +171,27 @@ export const StorageMenu = () => {
>
)}
+
-
-
Configuration} />
-
-
- Policies
+
+
Configuration} />
+
+
+ Policies
+
+
+ {IS_PLATFORM && (
+
+
+
+
Settings
+ {isListV2UpgradeAvailable && (
+
Upgrade available
+ )}
+
- {IS_PLATFORM && (
-
-
-
-
Settings
- {isListV2UpgradeAvailable && (
-
Upgrade available
- )}
-
-
-
- )}
-
+ )}
>
diff --git a/apps/studio/components/interfaces/TableGridEditor/SidePanelEditor/TableEditor/TableQuickstart/QuickstartTemplatesWidget.tsx b/apps/studio/components/interfaces/TableGridEditor/SidePanelEditor/TableEditor/TableQuickstart/QuickstartTemplatesWidget.tsx
index e4fb1ee0a31ce..14d2336a7755d 100644
--- a/apps/studio/components/interfaces/TableGridEditor/SidePanelEditor/TableEditor/TableQuickstart/QuickstartTemplatesWidget.tsx
+++ b/apps/studio/components/interfaces/TableGridEditor/SidePanelEditor/TableEditor/TableQuickstart/QuickstartTemplatesWidget.tsx
@@ -1,6 +1,7 @@
import { Columns3, Layers, Table2 } from 'lucide-react'
import { useCallback, useEffect, useState } from 'react'
import { toast } from 'sonner'
+
import { cn, Tooltip, TooltipContent, TooltipTrigger } from 'ui'
import type { TableField } from '../TableEditor.types'
import { tableTemplates } from './templates'
diff --git a/apps/studio/components/interfaces/TableGridEditor/SidePanelEditor/TableEditor/TableQuickstart/templates.ts b/apps/studio/components/interfaces/TableGridEditor/SidePanelEditor/TableEditor/TableQuickstart/templates.ts
index 68dd6dfe4da7a..27e101814b995 100644
--- a/apps/studio/components/interfaces/TableGridEditor/SidePanelEditor/TableEditor/TableQuickstart/templates.ts
+++ b/apps/studio/components/interfaces/TableGridEditor/SidePanelEditor/TableEditor/TableQuickstart/templates.ts
@@ -12,12 +12,7 @@ export const tableTemplates: Record
= {
isPrimary: true,
default: 'gen_random_uuid()',
},
- {
- name: 'user_id',
- type: 'uuid',
- nullable: false,
- unique: true,
- },
+ { name: 'user_id', type: 'uuid', nullable: false, unique: true },
{ name: 'username', type: 'text', nullable: true, unique: true },
{ name: 'display_name', type: 'text', nullable: true },
{ name: 'avatar_url', type: 'text', nullable: true },
@@ -40,11 +35,7 @@ export const tableTemplates: Record = {
isPrimary: true,
default: 'gen_random_uuid()',
},
- {
- name: 'author_id',
- type: 'uuid',
- nullable: false,
- },
+ { name: 'author_id', type: 'uuid', nullable: false },
{ name: 'content', type: 'text', nullable: false },
{ name: 'image_url', type: 'text', nullable: true },
{ name: 'likes_count', type: 'int4', nullable: false, default: '0' },
@@ -65,16 +56,8 @@ export const tableTemplates: Record = {
isPrimary: true,
default: 'gen_random_uuid()',
},
- {
- name: 'follower_id',
- type: 'uuid',
- nullable: false,
- },
- {
- name: 'following_id',
- type: 'uuid',
- nullable: false,
- },
+ { name: 'follower_id', type: 'uuid', nullable: false },
+ { name: 'following_id', type: 'uuid', nullable: false },
{ name: 'created_at', type: 'timestamptz', nullable: false, default: 'now()' },
],
rationale: 'Tracks relationships between followers and followed users',
@@ -120,12 +103,8 @@ export const tableTemplates: Record = {
default: 'gen_random_uuid()',
},
{ name: 'order_number', type: 'text', nullable: false, unique: true },
- {
- name: 'customer_id',
- type: 'uuid',
- nullable: false,
- },
- { name: 'status', type: 'text', nullable: false, default: "'pending'" },
+ { name: 'customer_id', type: 'uuid', nullable: false },
+ { name: 'status', type: 'text', nullable: false, default: 'pending' },
{ name: 'subtotal', type: 'numeric', nullable: false },
{ name: 'tax', type: 'numeric', nullable: false, default: '0' },
{ name: 'shipping', type: 'numeric', nullable: false, default: '0' },
@@ -147,16 +126,8 @@ export const tableTemplates: Record = {
isPrimary: true,
default: 'gen_random_uuid()',
},
- {
- name: 'user_id',
- type: 'uuid',
- nullable: false,
- },
- {
- name: 'product_id',
- type: 'uuid',
- nullable: false,
- },
+ { name: 'user_id', type: 'uuid', nullable: false },
+ { name: 'product_id', type: 'uuid', nullable: false },
{ name: 'quantity', type: 'int4', nullable: false, default: '1' },
{ name: 'added_at', type: 'timestamptz', nullable: false, default: 'now()' },
],
@@ -180,11 +151,7 @@ export const tableTemplates: Record = {
{ name: 'content', type: 'text', nullable: true },
{ name: 'excerpt', type: 'text', nullable: true },
{ name: 'cover_image', type: 'text', nullable: true },
- {
- name: 'author_id',
- type: 'uuid',
- nullable: false,
- },
+ { name: 'author_id', type: 'uuid', nullable: false },
{ name: 'status', type: 'text', nullable: false, default: "'draft'" },
{ name: 'published_at', type: 'timestamptz', nullable: true },
{ name: 'created_at', type: 'timestamptz', nullable: false, default: 'now()' },
@@ -222,11 +189,7 @@ export const tableTemplates: Record = {
isPrimary: true,
default: 'gen_random_uuid()',
},
- {
- name: 'article_id',
- type: 'uuid',
- nullable: false,
- },
+ { name: 'article_id', type: 'uuid', nullable: false },
{ name: 'author_name', type: 'text', nullable: false },
{ name: 'author_email', type: 'text', nullable: false },
{ name: 'content', type: 'text', nullable: false },
@@ -251,13 +214,9 @@ export const tableTemplates: Record = {
{ name: 'title', type: 'text', nullable: false },
{ name: 'description', type: 'text', nullable: true },
{ name: 'completed', type: 'bool', nullable: false, default: 'false' },
- { name: 'priority', type: 'text', nullable: true, default: "'medium'" },
+ { name: 'priority', type: 'text', nullable: true, default: 'medium' },
{ name: 'due_date', type: 'date', nullable: true },
- {
- name: 'user_id',
- type: 'uuid',
- nullable: false,
- },
+ { name: 'user_id', type: 'uuid', nullable: false },
{ name: 'list_id', type: 'uuid', nullable: true },
{ name: 'created_at', type: 'timestamptz', nullable: false, default: 'now()' },
{ name: 'updated_at', type: 'timestamptz', nullable: false, default: 'now()' },
@@ -279,11 +238,7 @@ export const tableTemplates: Record = {
{ name: 'description', type: 'text', nullable: true },
{ name: 'color', type: 'text', nullable: true },
{ name: 'icon', type: 'text', nullable: true },
- {
- name: 'user_id',
- type: 'uuid',
- nullable: false,
- },
+ { name: 'user_id', type: 'uuid', nullable: false },
{ name: 'created_at', type: 'timestamptz', nullable: false, default: 'now()' },
{ name: 'updated_at', type: 'timestamptz', nullable: false, default: 'now()' },
],
@@ -300,11 +255,7 @@ export const tableTemplates: Record = {
isPrimary: true,
default: 'gen_random_uuid()',
},
- {
- name: 'task_id',
- type: 'uuid',
- nullable: false,
- },
+ { name: 'task_id', type: 'uuid', nullable: false },
{ name: 'title', type: 'text', nullable: false },
{ name: 'completed', type: 'bool', nullable: false, default: 'false' },
{ name: 'position', type: 'int4', nullable: false, default: '0' },
@@ -325,11 +276,7 @@ export const tableTemplates: Record = {
isPrimary: true,
default: 'gen_random_uuid()',
},
- {
- name: 'user_id',
- type: 'uuid',
- nullable: true,
- },
+ { name: 'user_id', type: 'uuid', nullable: true },
{ name: 'session_id', type: 'text', nullable: true },
{ name: 'event_type', type: 'text', nullable: false },
{ name: 'properties', type: 'jsonb', nullable: true },
@@ -350,11 +297,7 @@ export const tableTemplates: Record = {
isPrimary: true,
default: 'gen_random_uuid()',
},
- {
- name: 'user_id',
- type: 'uuid',
- nullable: true,
- },
+ { name: 'user_id', type: 'uuid', nullable: true },
{ name: 'session_id', type: 'text', nullable: true },
{ name: 'path', type: 'text', nullable: false },
{ name: 'referrer', type: 'text', nullable: true },
diff --git a/apps/studio/components/layouts/AuthLayout/AuthEmailsLayout.tsx b/apps/studio/components/layouts/AuthLayout/AuthEmailsLayout.tsx
index fe69585fe33a0..1d2754ffc5c4a 100644
--- a/apps/studio/components/layouts/AuthLayout/AuthEmailsLayout.tsx
+++ b/apps/studio/components/layouts/AuthLayout/AuthEmailsLayout.tsx
@@ -8,6 +8,7 @@ import AuthLayout from './AuthLayout'
export const AuthEmailsLayout = ({ children }: PropsWithChildren<{}>) => {
const { ref } = useParams()
+
const showEmails = useIsFeatureEnabled('authentication:emails')
const navItems = [
diff --git a/apps/studio/components/layouts/Tabs/NewTab.tsx b/apps/studio/components/layouts/Tabs/NewTab.tsx
index 1eb98dc29ebf6..99dbe052b96db 100644
--- a/apps/studio/components/layouts/Tabs/NewTab.tsx
+++ b/apps/studio/components/layouts/Tabs/NewTab.tsx
@@ -20,7 +20,7 @@ import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
import { usePHFlag } from 'hooks/ui/useFlag'
import { uuidv4 } from 'lib/helpers'
import { useProfile } from 'lib/profile'
-import { useAiAssistantStateSnapshot, AssistantMessageType } from 'state/ai-assistant-state'
+import { AssistantMessageType, useAiAssistantStateSnapshot } from 'state/ai-assistant-state'
import { useSqlEditorV2StateSnapshot } from 'state/sql-editor-v2'
import { useTableEditorStateSnapshot } from 'state/table-editor'
import { createTabId, useTabsStateSnapshot } from 'state/tabs'
diff --git a/apps/studio/components/ui/DisabledWarningDueToIncident.tsx b/apps/studio/components/ui/DisabledWarningDueToIncident.tsx
deleted file mode 100644
index fc337e4a80ad3..0000000000000
--- a/apps/studio/components/ui/DisabledWarningDueToIncident.tsx
+++ /dev/null
@@ -1,29 +0,0 @@
-import InformationBox from 'components/ui/InformationBox'
-import { AlertCircle } from 'lucide-react'
-
-interface DisabledWarningDueToIncidentProps {
- title: string
-}
-
-const DisabledWarningDueToIncident = ({ title }: DisabledWarningDueToIncidentProps) => {
- return (
- }
- defaultVisibility={true}
- hideCollapse
- title={title}
- description={
-
- }
- />
- )
-}
-
-export default DisabledWarningDueToIncident
diff --git a/apps/studio/data/__templates/resource-query.ts b/apps/studio/data/__templates/resource-query.ts
index 0f0b0501376e9..2aff5ed875cda 100644
--- a/apps/studio/data/__templates/resource-query.ts
+++ b/apps/studio/data/__templates/resource-query.ts
@@ -33,14 +33,12 @@ export const useResourceQuery = (
{ projectRef, id }: ResourceVariables,
{ enabled = true, ...options }: UseQueryOptions = {}
) =>
- useQuery(
- resourceKeys.resource(projectRef, id),
- ({ signal }) => getResource({ projectRef, id }, signal),
- {
- enabled: enabled && typeof projectRef !== 'undefined' && typeof id !== 'undefined',
- ...options,
- }
- )
+ useQuery({
+ queryKey: resourceKeys.resource(projectRef, id),
+ queryFn: ({ signal }) => getResource({ projectRef, id }, signal),
+ enabled: enabled && typeof projectRef !== 'undefined' && typeof id !== 'undefined',
+ ...options,
+ })
/**
* useResourcePrefetch is used for prefetching data. For example, starting a query loading before a page is navigated to.
diff --git a/apps/studio/data/__templates/resource-update-mutation.ts b/apps/studio/data/__templates/resource-update-mutation.ts
index 0b8f26ff9976d..ef292042c981b 100644
--- a/apps/studio/data/__templates/resource-update-mutation.ts
+++ b/apps/studio/data/__templates/resource-update-mutation.ts
@@ -34,27 +34,25 @@ export const useResourceUpdateMutation = ({
> = {}) => {
const queryClient = useQueryClient()
- return useMutation(
- (vars) => updateResource(vars),
- {
- async onSuccess(data, variables, context) {
- const { projectRef, id } = variables
-
- await Promise.all([
- queryClient.invalidateQueries(resourceKeys.list(projectRef)),
- queryClient.invalidateQueries(resourceKeys.resource(projectRef, id)),
- ])
-
- await onSuccess?.(data, variables, context)
- },
- async onError(data, variables, context) {
- if (onError === undefined) {
- toast.error(`Failed to mutate: ${data.message}`)
- } else {
- onError(data, variables, context)
- }
- },
- ...options,
- }
- )
+ return useMutation({
+ mutationFn: (vars) => updateResource(vars),
+ async onSuccess(data, variables, context) {
+ const { projectRef, id } = variables
+
+ await Promise.all([
+ queryClient.invalidateQueries(resourceKeys.list(projectRef)),
+ queryClient.invalidateQueries(resourceKeys.resource(projectRef, id)),
+ ])
+
+ await onSuccess?.(data, variables, context)
+ },
+ async onError(data, variables, context) {
+ if (onError === undefined) {
+ toast.error(`Failed to mutate: ${data.message}`)
+ } else {
+ onError(data, variables, context)
+ }
+ },
+ ...options,
+ })
}
diff --git a/apps/studio/data/__templates/resources-query.ts b/apps/studio/data/__templates/resources-query.ts
index 9d15bd55ee77c..8e278b130184f 100644
--- a/apps/studio/data/__templates/resources-query.ts
+++ b/apps/studio/data/__templates/resources-query.ts
@@ -28,11 +28,12 @@ export const useResourcesQuery = (
{ projectRef }: ResourcesVariables,
{ enabled = true, ...options }: UseQueryOptions = {}
) =>
- useQuery(
- resourceKeys.list(projectRef),
- ({ signal }) => getResources({ projectRef }, signal),
- { enabled: enabled && typeof projectRef !== 'undefined', ...options }
- )
+ useQuery({
+ queryKey: resourceKeys.list(projectRef),
+ queryFn: ({ signal }) => getResources({ projectRef }, signal),
+ enabled: enabled && typeof projectRef !== 'undefined',
+ ...options,
+ })
/**
* useResourcesPrefetch is used for prefetching data. For example, starting a query loading before a page is navigated to.
diff --git a/apps/studio/data/access-tokens/access-tokens-create-mutation.ts b/apps/studio/data/access-tokens/access-tokens-create-mutation.ts
index c4f2d182383ac..6a0990ebf4a88 100644
--- a/apps/studio/data/access-tokens/access-tokens-create-mutation.ts
+++ b/apps/studio/data/access-tokens/access-tokens-create-mutation.ts
@@ -32,22 +32,20 @@ export const useAccessTokenCreateMutation = ({
> = {}) => {
const queryClient = useQueryClient()
- return useMutation(
- (vars) => createAccessToken(vars),
- {
- async onSuccess(data, variables, context) {
- await queryClient.invalidateQueries(accessTokenKeys.list())
-
- await onSuccess?.(data, variables, context)
- },
- async onError(data, variables, context) {
- if (onError === undefined) {
- toast.error(`Failed to create access token: ${data.message}`)
- } else {
- onError(data, variables, context)
- }
- },
- ...options,
- }
- )
+ return useMutation({
+ mutationFn: (vars) => createAccessToken(vars),
+ async onSuccess(data, variables, context) {
+ await queryClient.invalidateQueries(accessTokenKeys.list())
+
+ await onSuccess?.(data, variables, context)
+ },
+ async onError(data, variables, context) {
+ if (onError === undefined) {
+ toast.error(`Failed to create access token: ${data.message}`)
+ } else {
+ onError(data, variables, context)
+ }
+ },
+ ...options,
+ })
}
diff --git a/apps/studio/data/access-tokens/access-tokens-delete-mutation.ts b/apps/studio/data/access-tokens/access-tokens-delete-mutation.ts
index 8d536cd81a8f5..b4169903648f7 100644
--- a/apps/studio/data/access-tokens/access-tokens-delete-mutation.ts
+++ b/apps/studio/data/access-tokens/access-tokens-delete-mutation.ts
@@ -30,22 +30,20 @@ export const useAccessTokenDeleteMutation = ({
> = {}) => {
const queryClient = useQueryClient()
- return useMutation(
- (vars) => deleteAccessToken(vars),
- {
- async onSuccess(data, variables, context) {
- await queryClient.invalidateQueries(accessTokenKeys.list())
-
- await onSuccess?.(data, variables, context)
- },
- async onError(data, variables, context) {
- if (onError === undefined) {
- toast.error(`Failed to delete access token: ${data.message}`)
- } else {
- onError(data, variables, context)
- }
- },
- ...options,
- }
- )
+ return useMutation({
+ mutationFn: (vars) => deleteAccessToken(vars),
+ async onSuccess(data, variables, context) {
+ await queryClient.invalidateQueries(accessTokenKeys.list())
+
+ await onSuccess?.(data, variables, context)
+ },
+ async onError(data, variables, context) {
+ if (onError === undefined) {
+ toast.error(`Failed to delete access token: ${data.message}`)
+ } else {
+ onError(data, variables, context)
+ }
+ },
+ ...options,
+ })
}
diff --git a/apps/studio/data/access-tokens/access-tokens-query.ts b/apps/studio/data/access-tokens/access-tokens-query.ts
index 44deafedbbfae..7e882a7a170cd 100644
--- a/apps/studio/data/access-tokens/access-tokens-query.ts
+++ b/apps/studio/data/access-tokens/access-tokens-query.ts
@@ -21,8 +21,8 @@ export const useAccessTokensQuery = ({
enabled = true,
...options
}: UseQueryOptions = {}) =>
- useQuery(
- accessTokenKeys.list(),
- ({ signal }) => getAccessTokens(signal),
- options
- )
+ useQuery({
+ queryKey: accessTokenKeys.list(),
+ queryFn: ({ signal }) => getAccessTokens(signal),
+ ...options,
+ })
diff --git a/apps/studio/data/actions/action-detail-query.ts b/apps/studio/data/actions/action-detail-query.ts
index 4e34849c78faa..b2957ef8e5fd3 100644
--- a/apps/studio/data/actions/action-detail-query.ts
+++ b/apps/studio/data/actions/action-detail-query.ts
@@ -23,8 +23,10 @@ export const useActionRunQuery = (
{ ref, run_id }: ActionRunVariables,
{ enabled = true, ...options }: UseQueryOptions = {}
) =>
- useQuery(
- actionKeys.detail(ref, run_id),
- ({ signal }) => getActionRun({ ref, run_id }, signal),
- { enabled: enabled && Boolean(ref) && Boolean(run_id), staleTime: 0, ...options }
- )
+ useQuery({
+ queryKey: actionKeys.detail(ref, run_id),
+ queryFn: ({ signal }) => getActionRun({ ref, run_id }, signal),
+ enabled: enabled && Boolean(ref) && Boolean(run_id),
+ staleTime: 0,
+ ...options,
+ })
diff --git a/apps/studio/data/actions/action-logs-query.ts b/apps/studio/data/actions/action-logs-query.ts
index 218eed45a7293..27270834def79 100644
--- a/apps/studio/data/actions/action-logs-query.ts
+++ b/apps/studio/data/actions/action-logs-query.ts
@@ -29,8 +29,10 @@ export const useActionRunLogsQuery = (
{ ref, run_id }: ActionLogsVariables,
{ enabled = true, ...options }: UseQueryOptions = {}
) =>
- useQuery(
- actionKeys.detail(ref, run_id),
- ({ signal }) => getActionRunLogs({ ref, run_id }, signal),
- { enabled: enabled && Boolean(ref) && Boolean(run_id), staleTime: 0, ...options }
- )
+ useQuery({
+ queryKey: actionKeys.detail(ref, run_id),
+ queryFn: ({ signal }) => getActionRunLogs({ ref, run_id }, signal),
+ enabled: enabled && Boolean(ref) && Boolean(run_id),
+ staleTime: 0,
+ ...options,
+ })
diff --git a/apps/studio/data/actions/action-runs-query.ts b/apps/studio/data/actions/action-runs-query.ts
index d987fd3494d63..64bf56e2a2e06 100644
--- a/apps/studio/data/actions/action-runs-query.ts
+++ b/apps/studio/data/actions/action-runs-query.ts
@@ -27,8 +27,10 @@ export const useActionsQuery = (
{ ref }: ActionsVariables,
{ enabled = true, ...options }: UseQueryOptions = {}
) =>
- useQuery(
- actionKeys.list(ref),
- ({ signal }) => listActionRuns({ ref }, signal),
- { enabled: enabled && Boolean(ref), staleTime: 0, ...options }
- )
+ useQuery({
+ queryKey: actionKeys.list(ref),
+ queryFn: ({ signal }) => listActionRuns({ ref }, signal),
+ enabled: enabled && Boolean(ref),
+ staleTime: 0,
+ ...options,
+ })
diff --git a/apps/studio/data/ai/check-api-key-query.ts b/apps/studio/data/ai/check-api-key-query.ts
index 01c78a9af6ade..f0c9c61b58d0e 100644
--- a/apps/studio/data/ai/check-api-key-query.ts
+++ b/apps/studio/data/ai/check-api-key-query.ts
@@ -34,8 +34,9 @@ export const useCheckOpenAIKeyQuery = ({
enabled = true,
...options
}: UseQueryOptions = {}) =>
- useQuery(
- aiKeys.apiKey(),
- ({ signal }) => checkOpenAIKey(signal),
- { enabled: !IS_PLATFORM && enabled, ...options }
- )
+ useQuery({
+ queryKey: aiKeys.apiKey(),
+ queryFn: ({ signal }) => checkOpenAIKey(signal),
+ enabled: !IS_PLATFORM && enabled,
+ ...options,
+ })
diff --git a/apps/studio/data/ai/rate-message-mutation.ts b/apps/studio/data/ai/rate-message-mutation.ts
index 923943e6cfe99..8f9907723cff9 100644
--- a/apps/studio/data/ai/rate-message-mutation.ts
+++ b/apps/studio/data/ai/rate-message-mutation.ts
@@ -55,20 +55,18 @@ export const useRateMessageMutation = ({
UseMutationOptions,
'mutationFn'
> = {}) => {
- return useMutation(
- (vars) => rateMessage(vars),
- {
- async onSuccess(data, variables, context) {
- await onSuccess?.(data, variables, context)
- },
- async onError(data, variables, context) {
- if (onError === undefined) {
- console.error(`Failed to rate message: ${data.message}`)
- } else {
- onError(data, variables, context)
- }
- },
- ...options,
- }
- )
+ return useMutation({
+ mutationFn: (vars) => rateMessage(vars),
+ async onSuccess(data, variables, context) {
+ await onSuccess?.(data, variables, context)
+ },
+ async onError(data, variables, context) {
+ if (onError === undefined) {
+ console.error(`Failed to rate message: ${data.message}`)
+ } else {
+ onError(data, variables, context)
+ }
+ },
+ ...options,
+ })
}
diff --git a/apps/studio/data/ai/sql-cron-mutation.ts b/apps/studio/data/ai/sql-cron-mutation.ts
index 057dfe826aba2..c9c636b056898 100644
--- a/apps/studio/data/ai/sql-cron-mutation.ts
+++ b/apps/studio/data/ai/sql-cron-mutation.ts
@@ -44,20 +44,18 @@ export const useSqlCronGenerateMutation = ({
UseMutationOptions,
'mutationFn'
> = {}) => {
- return useMutation(
- (vars) => generateSqlCron(vars),
- {
- async onSuccess(data, variables, context) {
- await onSuccess?.(data, variables, context)
- },
- async onError(data, variables, context) {
- if (onError === undefined) {
- toast.error(`Failed to generate cron expression: ${data.message}`)
- } else {
- onError(data, variables, context)
- }
- },
- ...options,
- }
- )
+ return useMutation({
+ mutationFn: (vars) => generateSqlCron(vars),
+ async onSuccess(data, variables, context) {
+ await onSuccess?.(data, variables, context)
+ },
+ async onError(data, variables, context) {
+ if (onError === undefined) {
+ toast.error(`Failed to generate cron expression: ${data.message}`)
+ } else {
+ onError(data, variables, context)
+ }
+ },
+ ...options,
+ })
}
diff --git a/apps/studio/data/ai/sql-title-mutation.ts b/apps/studio/data/ai/sql-title-mutation.ts
index 45147665d9413..a5bf4c95044b0 100644
--- a/apps/studio/data/ai/sql-title-mutation.ts
+++ b/apps/studio/data/ai/sql-title-mutation.ts
@@ -48,20 +48,18 @@ export const useSqlTitleGenerateMutation = ({
UseMutationOptions,
'mutationFn'
> = {}) => {
- return useMutation(
- (vars) => generateSqlTitle(vars),
- {
- async onSuccess(data, variables, context) {
- await onSuccess?.(data, variables, context)
- },
- async onError(data, variables, context) {
- if (onError === undefined) {
- toast.error(`Failed to generate title: ${data.message}`)
- } else {
- onError(data, variables, context)
- }
- },
- ...options,
- }
- )
+ return useMutation({
+ mutationFn: (vars) => generateSqlTitle(vars),
+ async onSuccess(data, variables, context) {
+ await onSuccess?.(data, variables, context)
+ },
+ async onError(data, variables, context) {
+ if (onError === undefined) {
+ toast.error(`Failed to generate title: ${data.message}`)
+ } else {
+ onError(data, variables, context)
+ }
+ },
+ ...options,
+ })
}
diff --git a/apps/studio/data/analytics/functions-combined-stats-query.ts b/apps/studio/data/analytics/functions-combined-stats-query.ts
index edb4c095162a3..c9fa6f3810356 100644
--- a/apps/studio/data/analytics/functions-combined-stats-query.ts
+++ b/apps/studio/data/analytics/functions-combined-stats-query.ts
@@ -56,15 +56,14 @@ export const useFunctionsCombinedStatsQuery = = {}
) =>
- useQuery(
- analyticsKeys.functionsCombinedStats(projectRef, { functionId, interval }),
- ({ signal }) => getFunctionsCombinedStats({ projectRef, functionId, interval }, signal),
- {
- enabled:
- enabled &&
- typeof projectRef !== 'undefined' &&
- typeof functionId !== 'undefined' &&
- typeof interval !== 'undefined',
- ...options,
- }
- )
+ useQuery({
+ queryKey: analyticsKeys.functionsCombinedStats(projectRef, { functionId, interval }),
+ queryFn: ({ signal }) =>
+ getFunctionsCombinedStats({ projectRef, functionId, interval }, signal),
+ enabled:
+ enabled &&
+ typeof projectRef !== 'undefined' &&
+ typeof functionId !== 'undefined' &&
+ typeof interval !== 'undefined',
+ ...options,
+ })
diff --git a/apps/studio/data/analytics/functions-req-stats-query.ts b/apps/studio/data/analytics/functions-req-stats-query.ts
index 5a765b4148f43..0b974c4b12d24 100644
--- a/apps/studio/data/analytics/functions-req-stats-query.ts
+++ b/apps/studio/data/analytics/functions-req-stats-query.ts
@@ -56,15 +56,13 @@ export const useFunctionsReqStatsQuery = (
...options
}: UseQueryOptions = {}
) =>
- useQuery(
- analyticsKeys.functionsReqStats(projectRef, { functionId, interval }),
- ({ signal }) => getFunctionsReqStats({ projectRef, functionId, interval }, signal),
- {
- enabled:
- enabled &&
- typeof projectRef !== 'undefined' &&
- typeof functionId !== 'undefined' &&
- typeof interval !== 'undefined',
- ...options,
- }
- )
+ useQuery({
+ queryKey: analyticsKeys.functionsReqStats(projectRef, { functionId, interval }),
+ queryFn: ({ signal }) => getFunctionsReqStats({ projectRef, functionId, interval }, signal),
+ enabled:
+ enabled &&
+ typeof projectRef !== 'undefined' &&
+ typeof functionId !== 'undefined' &&
+ typeof interval !== 'undefined',
+ ...options,
+ })
diff --git a/apps/studio/data/analytics/functions-resource-usage-query.ts b/apps/studio/data/analytics/functions-resource-usage-query.ts
index ae767d52ebbd0..45d8d1a4f81d3 100644
--- a/apps/studio/data/analytics/functions-resource-usage-query.ts
+++ b/apps/studio/data/analytics/functions-resource-usage-query.ts
@@ -56,15 +56,14 @@ export const useFunctionsResourceUsageQuery = = {}
) =>
- useQuery(
- analyticsKeys.functionsResourceUsage(projectRef, { functionId, interval }),
- ({ signal }) => getFunctionsResourceUsage({ projectRef, functionId, interval }, signal),
- {
- enabled:
- enabled &&
- typeof projectRef !== 'undefined' &&
- typeof functionId !== 'undefined' &&
- typeof interval !== 'undefined',
- ...options,
- }
- )
+ useQuery({
+ queryKey: analyticsKeys.functionsResourceUsage(projectRef, { functionId, interval }),
+ queryFn: ({ signal }) =>
+ getFunctionsResourceUsage({ projectRef, functionId, interval }, signal),
+ enabled:
+ enabled &&
+ typeof projectRef !== 'undefined' &&
+ typeof functionId !== 'undefined' &&
+ typeof interval !== 'undefined',
+ ...options,
+ })
diff --git a/apps/studio/data/analytics/infra-monitoring-query.ts b/apps/studio/data/analytics/infra-monitoring-query.ts
index 00f607522d8a5..e57ecc3a50777 100644
--- a/apps/studio/data/analytics/infra-monitoring-query.ts
+++ b/apps/studio/data/analytics/infra-monitoring-query.ts
@@ -78,40 +78,38 @@ export const useInfraMonitoringQuery = (
...options
}: UseQueryOptions = {}
) =>
- useQuery(
- analyticsKeys.infraMonitoring(projectRef, {
+ useQuery({
+ queryKey: analyticsKeys.infraMonitoring(projectRef, {
attribute,
startDate,
endDate,
interval,
databaseIdentifier,
}),
- ({ signal }) =>
+ queryFn: ({ signal }) =>
getInfraMonitoring(
{ projectRef, attribute, startDate, endDate, interval, databaseIdentifier },
signal
),
- {
- enabled:
- enabled &&
- typeof projectRef !== 'undefined' &&
- typeof attribute !== 'undefined' &&
- typeof startDate !== 'undefined' &&
- typeof endDate !== 'undefined',
- select(data) {
- return {
- ...data,
- data: data.data.map((x) => {
- return {
- ...x,
- [attribute]:
- modifier !== undefined ? modifier(Number(x[attribute])) : Number(x[attribute]),
- periodStartFormatted: dayjs(x.period_start).format(dateFormat),
- }
- }),
- } as TData
- },
- staleTime: 1000 * 60, // default good for a minute
- ...options,
- }
- )
+ enabled:
+ enabled &&
+ typeof projectRef !== 'undefined' &&
+ typeof attribute !== 'undefined' &&
+ typeof startDate !== 'undefined' &&
+ typeof endDate !== 'undefined',
+ select(data) {
+ return {
+ ...data,
+ data: data.data.map((x) => {
+ return {
+ ...x,
+ [attribute]:
+ modifier !== undefined ? modifier(Number(x[attribute])) : Number(x[attribute]),
+ periodStartFormatted: dayjs(x.period_start).format(dateFormat),
+ }
+ }),
+ } as TData
+ },
+ staleTime: 1000 * 60,
+ ...options,
+ })
diff --git a/apps/studio/data/analytics/org-daily-stats-query.ts b/apps/studio/data/analytics/org-daily-stats-query.ts
index db4fd96f2ac12..ae80bcf4c0682 100644
--- a/apps/studio/data/analytics/org-daily-stats-query.ts
+++ b/apps/studio/data/analytics/org-daily-stats-query.ts
@@ -151,16 +151,14 @@ export const useOrgDailyStatsQuery = (
{ orgSlug, startDate, endDate, projectRef }: OrgDailyStatsVariables,
{ enabled = true, ...options }: UseQueryOptions = {}
) =>
- useQuery(
- analyticsKeys.orgDailyStats(orgSlug, { startDate, endDate, projectRef }),
- ({ signal }) => getOrgDailyStats({ orgSlug, startDate, endDate, projectRef }, signal),
- {
- enabled:
- enabled &&
- typeof orgSlug !== 'undefined' &&
- typeof startDate !== 'undefined' &&
- typeof endDate !== 'undefined',
- staleTime: 1000 * 60 * 60, // default good for an hour for now
- ...options,
- }
- )
+ useQuery({
+ queryKey: analyticsKeys.orgDailyStats(orgSlug, { startDate, endDate, projectRef }),
+ queryFn: ({ signal }) => getOrgDailyStats({ orgSlug, startDate, endDate, projectRef }, signal),
+ enabled:
+ enabled &&
+ typeof orgSlug !== 'undefined' &&
+ typeof startDate !== 'undefined' &&
+ typeof endDate !== 'undefined',
+ staleTime: 1000 * 60 * 60,
+ ...options,
+ })
diff --git a/apps/studio/data/analytics/project-daily-stats-query.ts b/apps/studio/data/analytics/project-daily-stats-query.ts
index f8bda24d30115..610a87397ca2f 100644
--- a/apps/studio/data/analytics/project-daily-stats-query.ts
+++ b/apps/studio/data/analytics/project-daily-stats-query.ts
@@ -50,21 +50,20 @@ export const useProjectDailyStatsQuery = (
...options
}: UseQueryOptions = {}
) =>
- useQuery(
- analyticsKeys.infraMonitoring(projectRef, {
+ useQuery({
+ queryKey: analyticsKeys.infraMonitoring(projectRef, {
attribute,
startDate,
endDate,
}),
- ({ signal }) => getProjectDailyStats({ projectRef, attribute, startDate, endDate }, signal),
- {
- enabled:
- enabled &&
- typeof projectRef !== 'undefined' &&
- typeof attribute !== 'undefined' &&
- typeof startDate !== 'undefined' &&
- typeof endDate !== 'undefined',
- staleTime: 1000 * 60 * 30, // default good for 30m, stats only refresh once a day
- ...options,
- }
- )
+ queryFn: ({ signal }) =>
+ getProjectDailyStats({ projectRef, attribute, startDate, endDate }, signal),
+ enabled:
+ enabled &&
+ typeof projectRef !== 'undefined' &&
+ typeof attribute !== 'undefined' &&
+ typeof startDate !== 'undefined' &&
+ typeof endDate !== 'undefined',
+ staleTime: 1000 * 60 * 30,
+ ...options,
+ })
diff --git a/apps/studio/data/analytics/project-log-requests-count-query.ts b/apps/studio/data/analytics/project-log-requests-count-query.ts
index 0d6e5b5863dbb..8898c8a227a73 100644
--- a/apps/studio/data/analytics/project-log-requests-count-query.ts
+++ b/apps/studio/data/analytics/project-log-requests-count-query.ts
@@ -40,14 +40,12 @@ export const useProjectLogRequestsCountQuery = = {}
) =>
- useQuery(
- analyticsKeys.usageApiRequestsCount(projectRef),
- ({ signal }) => getProjectLogRequestsCountStats({ projectRef }, signal),
- {
- enabled: enabled && typeof projectRef !== 'undefined',
- ...options,
- }
- )
+ useQuery({
+ queryKey: analyticsKeys.usageApiRequestsCount(projectRef),
+ queryFn: ({ signal }) => getProjectLogRequestsCountStats({ projectRef }, signal),
+ enabled: enabled && typeof projectRef !== 'undefined',
+ ...options,
+ })
export function prefetchProjectLogRequestsCount(
client: QueryClient,
diff --git a/apps/studio/data/analytics/project-log-stats-query.ts b/apps/studio/data/analytics/project-log-stats-query.ts
index 76167f33d9eec..be3379ef52159 100644
--- a/apps/studio/data/analytics/project-log-stats-query.ts
+++ b/apps/studio/data/analytics/project-log-stats-query.ts
@@ -60,14 +60,12 @@ export const useProjectLogStatsQuery = (
...options
}: UseQueryOptions = {}
) =>
- useQuery(
- analyticsKeys.usageApiCounts(projectRef, interval),
- ({ signal }) => getProjectLogStats({ projectRef, interval }, signal),
- {
- enabled: enabled && typeof projectRef !== 'undefined' && typeof interval !== 'undefined',
- ...options,
- }
- )
+ useQuery({
+ queryKey: analyticsKeys.usageApiCounts(projectRef, interval),
+ queryFn: ({ signal }) => getProjectLogStats({ projectRef, interval }, signal),
+ enabled: enabled && typeof projectRef !== 'undefined' && typeof interval !== 'undefined',
+ ...options,
+ })
export function prefetchProjectLogStats(
client: QueryClient,
diff --git a/apps/studio/data/api-authorization/api-authorization-approve-mutation.ts b/apps/studio/data/api-authorization/api-authorization-approve-mutation.ts
index 56f52c2eafe1e..832c71149b5e0 100644
--- a/apps/studio/data/api-authorization/api-authorization-approve-mutation.ts
+++ b/apps/studio/data/api-authorization/api-authorization-approve-mutation.ts
@@ -36,17 +36,15 @@ export const useApiAuthorizationApproveMutation = ({
UseMutationOptions,
'mutationFn'
> = {}) => {
- return useMutation(
- (vars) => approveApiAuthorization(vars),
- {
- async onError(data, variables, context) {
- if (onError === undefined) {
- toast.error(`Failed to approve authorization request: ${data.message}`)
- } else {
- onError(data, variables, context)
- }
- },
- ...options,
- }
- )
+ return useMutation({
+ mutationFn: (vars) => approveApiAuthorization(vars),
+ async onError(data, variables, context) {
+ if (onError === undefined) {
+ toast.error(`Failed to approve authorization request: ${data.message}`)
+ } else {
+ onError(data, variables, context)
+ }
+ },
+ ...options,
+ })
}
diff --git a/apps/studio/data/api-authorization/api-authorization-decline-mutation.ts b/apps/studio/data/api-authorization/api-authorization-decline-mutation.ts
index 7976a7d94af55..bf1eec660ec10 100644
--- a/apps/studio/data/api-authorization/api-authorization-decline-mutation.ts
+++ b/apps/studio/data/api-authorization/api-authorization-decline-mutation.ts
@@ -35,17 +35,15 @@ export const useApiAuthorizationDeclineMutation = ({
UseMutationOptions,
'mutationFn'
> = {}) => {
- return useMutation(
- (vars) => declineApiAuthorization(vars),
- {
- async onError(data, variables, context) {
- if (onError === undefined) {
- toast.error(`Failed to decline authorization request: ${data.message}`)
- } else {
- onError(data, variables, context)
- }
- },
- ...options,
- }
- )
+ return useMutation({
+ mutationFn: (vars) => declineApiAuthorization(vars),
+ async onError(data, variables, context) {
+ if (onError === undefined) {
+ toast.error(`Failed to decline authorization request: ${data.message}`)
+ } else {
+ onError(data, variables, context)
+ }
+ },
+ ...options,
+ })
}
diff --git a/apps/studio/data/api-authorization/api-authorization-query.ts b/apps/studio/data/api-authorization/api-authorization-query.ts
index 37d0f58356c04..bfe1f9a7cc6be 100644
--- a/apps/studio/data/api-authorization/api-authorization-query.ts
+++ b/apps/studio/data/api-authorization/api-authorization-query.ts
@@ -42,11 +42,9 @@ export const useApiAuthorizationQuery = (
{ id }: ApiAuthorizationVariables,
{ enabled = true, ...options }: UseQueryOptions = {}
) =>
- useQuery(
- resourceKeys.resource(id),
- ({ signal }) => getApiAuthorizationDetails({ id }, signal),
- {
- enabled: enabled && typeof id !== 'undefined',
- ...options,
- }
- )
+ useQuery({
+ queryKey: resourceKeys.resource(id),
+ queryFn: ({ signal }) => getApiAuthorizationDetails({ id }, signal),
+ enabled: enabled && typeof id !== 'undefined',
+ ...options,
+ })
diff --git a/apps/studio/data/api-keys/[id]/api-key-id-query.ts b/apps/studio/data/api-keys/[id]/api-key-id-query.ts
index 06aae547d139f..87ab4073ae8a8 100644
--- a/apps/studio/data/api-keys/[id]/api-key-id-query.ts
+++ b/apps/studio/data/api-keys/[id]/api-key-id-query.ts
@@ -37,11 +37,9 @@ export const useAPIKeyIdQuery = (
{ projectRef, id, reveal }: APIKeyVariables,
{ enabled = true, ...options }: UseQueryOptions = {}
) =>
- useQuery(
- apiKeysKeys.single(projectRef, id),
- ({ signal }) => getAPIKeysById({ projectRef, id, reveal }, signal),
- {
- enabled: enabled && typeof projectRef !== 'undefined' && typeof id !== 'undefined',
- ...options,
- }
- )
+ useQuery({
+ queryKey: apiKeysKeys.single(projectRef, id),
+ queryFn: ({ signal }) => getAPIKeysById({ projectRef, id, reveal }, signal),
+ enabled: enabled && typeof projectRef !== 'undefined' && typeof id !== 'undefined',
+ ...options,
+ })
diff --git a/apps/studio/data/api-keys/[id]/api-key-id-update-mutation.ts b/apps/studio/data/api-keys/[id]/api-key-id-update-mutation.ts
index 18751a12448d3..05cee5366a8c6 100644
--- a/apps/studio/data/api-keys/[id]/api-key-id-update-mutation.ts
+++ b/apps/studio/data/api-keys/[id]/api-key-id-update-mutation.ts
@@ -47,24 +47,22 @@ export const useResourceUpdateMutation = ({
> = {}) => {
const queryClient = useQueryClient()
- return useMutation(
- (vars) => updateAPIKeysById(vars),
- {
- async onSuccess(data, variables, context) {
- const { projectRef, id } = variables
+ return useMutation({
+ mutationFn: (vars) => updateAPIKeysById(vars),
+ async onSuccess(data, variables, context) {
+ const { projectRef, id } = variables
- await queryClient.invalidateQueries(apiKeysKeys.list(projectRef))
+ await queryClient.invalidateQueries(apiKeysKeys.list(projectRef))
- await onSuccess?.(data, variables, context)
- },
- async onError(data, variables, context) {
- if (onError === undefined) {
- toast.error(`Failed to mutate: ${data.message}`)
- } else {
- onError(data, variables, context)
- }
- },
- ...options,
- }
- )
+ await onSuccess?.(data, variables, context)
+ },
+ async onError(data, variables, context) {
+ if (onError === undefined) {
+ toast.error(`Failed to mutate: ${data.message}`)
+ } else {
+ onError(data, variables, context)
+ }
+ },
+ ...options,
+ })
}
diff --git a/apps/studio/data/api-keys/api-key-create-mutation.ts b/apps/studio/data/api-keys/api-key-create-mutation.ts
index f84d56055ec57..b5838231537df 100644
--- a/apps/studio/data/api-keys/api-key-create-mutation.ts
+++ b/apps/studio/data/api-keys/api-key-create-mutation.ts
@@ -63,24 +63,22 @@ export const useAPIKeyCreateMutation = ({
> = {}) => {
const queryClient = useQueryClient()
- return useMutation(
- (vars) => createAPIKey(vars),
- {
- async onSuccess(data, variables, context) {
- const { projectRef } = variables
+ return useMutation({
+ mutationFn: (vars) => createAPIKey(vars),
+ async onSuccess(data, variables, context) {
+ const { projectRef } = variables
- await queryClient.invalidateQueries(apiKeysKeys.list(projectRef))
+ await queryClient.invalidateQueries(apiKeysKeys.list(projectRef))
- await onSuccess?.(data, variables, context)
- },
- async onError(data, variables, context) {
- if (onError === undefined) {
- toast.error(`Failed to create API key: ${data.message}`)
- } else {
- onError(data, variables, context)
- }
- },
- ...options,
- }
- )
+ await onSuccess?.(data, variables, context)
+ },
+ async onError(data, variables, context) {
+ if (onError === undefined) {
+ toast.error(`Failed to create API key: ${data.message}`)
+ } else {
+ onError(data, variables, context)
+ }
+ },
+ ...options,
+ })
}
diff --git a/apps/studio/data/api-keys/api-key-delete-mutation.ts b/apps/studio/data/api-keys/api-key-delete-mutation.ts
index 0625eab78d086..d85ab96687f0c 100644
--- a/apps/studio/data/api-keys/api-key-delete-mutation.ts
+++ b/apps/studio/data/api-keys/api-key-delete-mutation.ts
@@ -35,24 +35,22 @@ export const useAPIKeyDeleteMutation = ({
> = {}) => {
const queryClient = useQueryClient()
- return useMutation(
- (vars) => deleteAPIKey(vars),
- {
- async onSuccess(data, variables, context) {
- const { projectRef } = variables
-
- await queryClient.invalidateQueries(apiKeysKeys.list(projectRef))
-
- await onSuccess?.(data, variables, context)
- },
- async onError(data, variables, context) {
- if (onError === undefined) {
- toast.error(`Failed to delete API key: ${data.message}`)
- } else {
- onError(data, variables, context)
- }
- },
- ...options,
- }
- )
+ return useMutation({
+ mutationFn: (vars) => deleteAPIKey(vars),
+ async onSuccess(data, variables, context) {
+ const { projectRef } = variables
+
+ await queryClient.invalidateQueries(apiKeysKeys.list(projectRef))
+
+ await onSuccess?.(data, variables, context)
+ },
+ async onError(data, variables, context) {
+ if (onError === undefined) {
+ toast.error(`Failed to delete API key: ${data.message}`)
+ } else {
+ onError(data, variables, context)
+ }
+ },
+ ...options,
+ })
}
diff --git a/apps/studio/data/api-keys/api-keys-query.ts b/apps/studio/data/api-keys/api-keys-query.ts
index 5b746e88be730..596ae00710bfa 100644
--- a/apps/studio/data/api-keys/api-keys-query.ts
+++ b/apps/studio/data/api-keys/api-keys-query.ts
@@ -70,14 +70,12 @@ export const useAPIKeysQuery = (
{ projectRef, reveal = false }: APIKeysVariables,
{ enabled = true, ...options }: UseQueryOptions = {}
) => {
- return useQuery(
- apiKeysKeys.list(projectRef, reveal),
- ({ signal }) => getAPIKeys({ projectRef, reveal }, signal),
- {
- enabled: enabled && typeof projectRef !== 'undefined',
- ...options,
- }
- )
+ return useQuery({
+ queryKey: apiKeysKeys.list(projectRef, reveal),
+ queryFn: ({ signal }) => getAPIKeys({ projectRef, reveal }, signal),
+ enabled: enabled && typeof projectRef !== 'undefined',
+ ...options,
+ })
}
export const getKeys = (apiKeys: APIKey[] = []) => {
diff --git a/apps/studio/data/api-keys/legacy-api-key-toggle-mutation.ts b/apps/studio/data/api-keys/legacy-api-key-toggle-mutation.ts
index 0f0a07c43e37b..fc2a370a6063e 100644
--- a/apps/studio/data/api-keys/legacy-api-key-toggle-mutation.ts
+++ b/apps/studio/data/api-keys/legacy-api-key-toggle-mutation.ts
@@ -35,26 +35,24 @@ export const useToggleLegacyAPIKeysMutation = ({
> = {}) => {
const queryClient = useQueryClient()
- return useMutation(
- (vars) => toggleLegacyAPIKeys(vars),
- {
- async onSuccess(data, variables, context) {
- const { projectRef } = variables
-
- await queryClient.invalidateQueries(apiKeysKeys.status(projectRef))
-
- await onSuccess?.(data, variables, context)
- },
- async onError(data, variables, context) {
- if (onError === undefined) {
- toast.error(
- `Failed to ${variables.enabled ? 're-enable' : 'disable'} JWT-based API keys: ${data.message}`
- )
- } else {
- onError(data, variables, context)
- }
- },
- ...options,
- }
- )
+ return useMutation({
+ mutationFn: (vars) => toggleLegacyAPIKeys(vars),
+ async onSuccess(data, variables, context) {
+ const { projectRef } = variables
+
+ await queryClient.invalidateQueries(apiKeysKeys.status(projectRef))
+
+ await onSuccess?.(data, variables, context)
+ },
+ async onError(data, variables, context) {
+ if (onError === undefined) {
+ toast.error(
+ `Failed to ${variables.enabled ? 're-enable' : 'disable'} JWT-based API keys: ${data.message}`
+ )
+ } else {
+ onError(data, variables, context)
+ }
+ },
+ ...options,
+ })
}
diff --git a/apps/studio/data/api-keys/legacy-api-keys-status-query.ts b/apps/studio/data/api-keys/legacy-api-keys-status-query.ts
index 73f509780f126..9d314ea54074f 100644
--- a/apps/studio/data/api-keys/legacy-api-keys-status-query.ts
+++ b/apps/studio/data/api-keys/legacy-api-keys-status-query.ts
@@ -33,11 +33,9 @@ export const useLegacyAPIKeysStatusQuery = (
...options
}: UseQueryOptions = {}
) =>
- useQuery(
- apiKeysKeys.status(projectRef),
- ({ signal }) => getLegacyAPIKeysStatus({ projectRef }, signal),
- {
- enabled: IS_PLATFORM && enabled && typeof projectRef !== 'undefined',
- ...options,
- }
- )
+ useQuery({
+ queryKey: apiKeysKeys.status(projectRef),
+ queryFn: ({ signal }) => getLegacyAPIKeysStatus({ projectRef }, signal),
+ enabled: IS_PLATFORM && enabled && typeof projectRef !== 'undefined',
+ ...options,
+ })
diff --git a/apps/studio/data/api-settings/create-and-expose-api-schema-mutation.ts b/apps/studio/data/api-settings/create-and-expose-api-schema-mutation.ts
index c3f2f2c0b5365..60946310a3489 100644
--- a/apps/studio/data/api-settings/create-and-expose-api-schema-mutation.ts
+++ b/apps/studio/data/api-settings/create-and-expose-api-schema-mutation.ts
@@ -65,7 +65,8 @@ export const useCreateAndExposeAPISchemaMutation = ({
CreateAndExposeAPISchemaData,
ResponseError,
CreateAndExposeAPISchemaVariables
- >((vars) => createAndExposeApiSchema(vars), {
+ >({
+ mutationFn: (vars) => createAndExposeApiSchema(vars),
async onSuccess(data, variables, context) {
const { projectRef } = variables
await Promise.all([
diff --git a/apps/studio/data/auth/auth-config-query.ts b/apps/studio/data/auth/auth-config-query.ts
index 337b30f4bac04..9d84e0634dfc1 100644
--- a/apps/studio/data/auth/auth-config-query.ts
+++ b/apps/studio/data/auth/auth-config-query.ts
@@ -37,14 +37,12 @@ export const useAuthConfigQuery = (
...options
}: UseQueryOptions = {}
) =>
- useQuery(
- authKeys.authConfig(projectRef),
- ({ signal }) => getProjectAuthConfig({ projectRef }, signal),
- {
- enabled: enabled && IS_PLATFORM && typeof projectRef !== 'undefined',
- ...options,
- }
- )
+ useQuery({
+ queryKey: authKeys.authConfig(projectRef),
+ queryFn: ({ signal }) => getProjectAuthConfig({ projectRef }, signal),
+ enabled: enabled && IS_PLATFORM && typeof projectRef !== 'undefined',
+ ...options,
+ })
export const useAuthConfigPrefetch = ({ projectRef }: AuthConfigVariables) => {
const client = useQueryClient()
diff --git a/apps/studio/data/auth/auth-config-update-mutation.ts b/apps/studio/data/auth/auth-config-update-mutation.ts
index 6d4e15979833c..019bfe1699a39 100644
--- a/apps/studio/data/auth/auth-config-update-mutation.ts
+++ b/apps/studio/data/auth/auth-config-update-mutation.ts
@@ -37,22 +37,20 @@ export const useAuthConfigUpdateMutation = ({
> = {}) => {
const queryClient = useQueryClient()
- return useMutation(
- (vars) => updateAuthConfig(vars),
- {
- async onSuccess(data, variables, context) {
- const { projectRef } = variables
- await queryClient.invalidateQueries(authKeys.authConfig(projectRef))
- await onSuccess?.(data, variables, context)
- },
- async onError(data, variables, context) {
- if (onError === undefined) {
- toast.error(`Failed to update auth configuration: ${data.message}`)
- } else {
- onError(data, variables, context)
- }
- },
- ...options,
- }
- )
+ return useMutation({
+ mutationFn: (vars) => updateAuthConfig(vars),
+ async onSuccess(data, variables, context) {
+ const { projectRef } = variables
+ await queryClient.invalidateQueries(authKeys.authConfig(projectRef))
+ await onSuccess?.(data, variables, context)
+ },
+ async onError(data, variables, context) {
+ if (onError === undefined) {
+ toast.error(`Failed to update auth configuration: ${data.message}`)
+ } else {
+ onError(data, variables, context)
+ }
+ },
+ ...options,
+ })
}
diff --git a/apps/studio/data/auth/auth-hooks-update-mutation.ts b/apps/studio/data/auth/auth-hooks-update-mutation.ts
index 8b8ebecffe645..535901a9615ec 100644
--- a/apps/studio/data/auth/auth-hooks-update-mutation.ts
+++ b/apps/studio/data/auth/auth-hooks-update-mutation.ts
@@ -33,22 +33,20 @@ export const useAuthHooksUpdateMutation = ({
> = {}) => {
const queryClient = useQueryClient()
- return useMutation(
- (vars) => updateAuthHooks(vars),
- {
- async onSuccess(data, variables, context) {
- const { projectRef } = variables
- await queryClient.invalidateQueries(authKeys.authConfig(projectRef))
- await onSuccess?.(data, variables, context)
- },
- async onError(data, variables, context) {
- if (onError === undefined) {
- toast.error(`Failed to update auth hooks: ${data.message}`)
- } else {
- onError(data, variables, context)
- }
- },
- ...options,
- }
- )
+ return useMutation({
+ mutationFn: (vars) => updateAuthHooks(vars),
+ async onSuccess(data, variables, context) {
+ const { projectRef } = variables
+ await queryClient.invalidateQueries(authKeys.authConfig(projectRef))
+ await onSuccess?.(data, variables, context)
+ },
+ async onError(data, variables, context) {
+ if (onError === undefined) {
+ toast.error(`Failed to update auth hooks: ${data.message}`)
+ } else {
+ onError(data, variables, context)
+ }
+ },
+ ...options,
+ })
}
diff --git a/apps/studio/data/auth/session-access-token-query.ts b/apps/studio/data/auth/session-access-token-query.ts
index 095a57d48fa16..c5f042e128846 100644
--- a/apps/studio/data/auth/session-access-token-query.ts
+++ b/apps/studio/data/auth/session-access-token-query.ts
@@ -22,8 +22,8 @@ export const useSessionAccessTokenQuery = ({
enabled = true,
...options
}: UseQueryOptions = {}) =>
- useQuery(
- authKeys.accessToken(),
- () => getSessionAccessToken(),
- options
- )
+ useQuery({
+ queryKey: authKeys.accessToken(),
+ queryFn: () => getSessionAccessToken(),
+ ...options,
+ })
diff --git a/apps/studio/data/auth/user-create-mutation.ts b/apps/studio/data/auth/user-create-mutation.ts
index 533c8e2df418b..1db52c575a9c6 100644
--- a/apps/studio/data/auth/user-create-mutation.ts
+++ b/apps/studio/data/auth/user-create-mutation.ts
@@ -39,24 +39,22 @@ export const useUserCreateMutation = ({
> = {}) => {
const queryClient = useQueryClient()
- return useMutation(
- (vars) => createUser(vars),
- {
- async onSuccess(data, variables, context) {
- const { projectRef } = variables
-
- await Promise.all([queryClient.invalidateQueries(authKeys.usersInfinite(projectRef))])
-
- await onSuccess?.(data, variables, context)
- },
- async onError(data, variables, context) {
- if (onError === undefined) {
- toast.error(`Failed to create user: ${data.message}`)
- } else {
- onError(data, variables, context)
- }
- },
- ...options,
- }
- )
+ return useMutation({
+ mutationFn: (vars) => createUser(vars),
+ async onSuccess(data, variables, context) {
+ const { projectRef } = variables
+
+ await Promise.all([queryClient.invalidateQueries(authKeys.usersInfinite(projectRef))])
+
+ await onSuccess?.(data, variables, context)
+ },
+ async onError(data, variables, context) {
+ if (onError === undefined) {
+ toast.error(`Failed to create user: ${data.message}`)
+ } else {
+ onError(data, variables, context)
+ }
+ },
+ ...options,
+ })
}
diff --git a/apps/studio/data/auth/user-delete-mfa-factors-mutation.ts b/apps/studio/data/auth/user-delete-mfa-factors-mutation.ts
index 149952ad71a9c..7ae5937528b43 100644
--- a/apps/studio/data/auth/user-delete-mfa-factors-mutation.ts
+++ b/apps/studio/data/auth/user-delete-mfa-factors-mutation.ts
@@ -29,21 +29,19 @@ export const useUserDeleteMFAFactorsMutation = ({
UseMutationOptions,
'mutationFn'
> = {}) => {
- return useMutation(
- (vars) => deleteMFAFactors(vars),
- {
- async onSuccess(data, variables, context) {
- // [Joshen] If we need to invalidate any queries
- await onSuccess?.(data, variables, context)
- },
- async onError(data, variables, context) {
- if (onError === undefined) {
- toast.error(`Failed to delete the user's MFA factors: ${data.message}`)
- } else {
- onError(data, variables, context)
- }
- },
- ...options,
- }
- )
+ return useMutation({
+ mutationFn: (vars) => deleteMFAFactors(vars),
+ async onSuccess(data, variables, context) {
+ // [Joshen] If we need to invalidate any queries
+ await onSuccess?.(data, variables, context)
+ },
+ async onError(data, variables, context) {
+ if (onError === undefined) {
+ toast.error(`Failed to delete the user's MFA factors: ${data.message}`)
+ } else {
+ onError(data, variables, context)
+ }
+ },
+ ...options,
+ })
}
diff --git a/apps/studio/data/auth/user-delete-mutation.ts b/apps/studio/data/auth/user-delete-mutation.ts
index 0b67188f05238..62e0c671fc27d 100644
--- a/apps/studio/data/auth/user-delete-mutation.ts
+++ b/apps/studio/data/auth/user-delete-mutation.ts
@@ -31,26 +31,24 @@ export const useUserDeleteMutation = ({
> = {}) => {
const queryClient = useQueryClient()
- return useMutation(
- (vars) => deleteUser(vars),
- {
- async onSuccess(data, variables, context) {
- const { projectRef, skipInvalidation = false } = variables
-
- if (!skipInvalidation) {
- await Promise.all([queryClient.invalidateQueries(authKeys.usersInfinite(projectRef))])
- }
-
- await onSuccess?.(data, variables, context)
- },
- async onError(data, variables, context) {
- if (onError === undefined) {
- toast.error(`Failed to delete user: ${data.message}`)
- } else {
- onError(data, variables, context)
- }
- },
- ...options,
- }
- )
+ return useMutation({
+ mutationFn: (vars) => deleteUser(vars),
+ async onSuccess(data, variables, context) {
+ const { projectRef, skipInvalidation = false } = variables
+
+ if (!skipInvalidation) {
+ await Promise.all([queryClient.invalidateQueries(authKeys.usersInfinite(projectRef))])
+ }
+
+ await onSuccess?.(data, variables, context)
+ },
+ async onError(data, variables, context) {
+ if (onError === undefined) {
+ toast.error(`Failed to delete user: ${data.message}`)
+ } else {
+ onError(data, variables, context)
+ }
+ },
+ ...options,
+ })
}
diff --git a/apps/studio/data/auth/user-invite-mutation.ts b/apps/studio/data/auth/user-invite-mutation.ts
index 42bff571c6d76..77fcfd13e3116 100644
--- a/apps/studio/data/auth/user-invite-mutation.ts
+++ b/apps/studio/data/auth/user-invite-mutation.ts
@@ -31,24 +31,22 @@ export const useUserInviteMutation = ({
> = {}) => {
const queryClient = useQueryClient()
- return useMutation(
- (vars) => inviteUser(vars),
- {
- async onSuccess(data, variables, context) {
- const { projectRef } = variables
-
- await Promise.all([queryClient.invalidateQueries(authKeys.usersInfinite(projectRef))])
-
- await onSuccess?.(data, variables, context)
- },
- async onError(data, variables, context) {
- if (onError === undefined) {
- toast.error(`Failed to invite user: ${data.message}`)
- } else {
- onError(data, variables, context)
- }
- },
- ...options,
- }
- )
+ return useMutation({
+ mutationFn: (vars) => inviteUser(vars),
+ async onSuccess(data, variables, context) {
+ const { projectRef } = variables
+
+ await Promise.all([queryClient.invalidateQueries(authKeys.usersInfinite(projectRef))])
+
+ await onSuccess?.(data, variables, context)
+ },
+ async onError(data, variables, context) {
+ if (onError === undefined) {
+ toast.error(`Failed to invite user: ${data.message}`)
+ } else {
+ onError(data, variables, context)
+ }
+ },
+ ...options,
+ })
}
diff --git a/apps/studio/data/auth/user-reset-password-mutation.ts b/apps/studio/data/auth/user-reset-password-mutation.ts
index aeaef00b5d8b6..d39a5a9a692e0 100644
--- a/apps/studio/data/auth/user-reset-password-mutation.ts
+++ b/apps/studio/data/auth/user-reset-password-mutation.ts
@@ -31,21 +31,19 @@ export const useUserResetPasswordMutation = ({
UseMutationOptions,
'mutationFn'
> = {}) => {
- return useMutation(
- (vars) => resetPassword(vars),
- {
- async onSuccess(data, variables, context) {
- // [Joshen] If we need to invalidate any queries
- await onSuccess?.(data, variables, context)
- },
- async onError(data, variables, context) {
- if (onError === undefined) {
- toast.error(`Failed to reset user password: ${data.message}`)
- } else {
- onError(data, variables, context)
- }
- },
- ...options,
- }
- )
+ return useMutation({
+ mutationFn: (vars) => resetPassword(vars),
+ async onSuccess(data, variables, context) {
+ // [Joshen] If we need to invalidate any queries
+ await onSuccess?.(data, variables, context)
+ },
+ async onError(data, variables, context) {
+ if (onError === undefined) {
+ toast.error(`Failed to reset user password: ${data.message}`)
+ } else {
+ onError(data, variables, context)
+ }
+ },
+ ...options,
+ })
}
diff --git a/apps/studio/data/auth/user-send-magic-link-mutation.ts b/apps/studio/data/auth/user-send-magic-link-mutation.ts
index 22037ab8938fc..127fb33a313c9 100644
--- a/apps/studio/data/auth/user-send-magic-link-mutation.ts
+++ b/apps/studio/data/auth/user-send-magic-link-mutation.ts
@@ -31,21 +31,19 @@ export const useUserSendMagicLinkMutation = ({
UseMutationOptions,
'mutationFn'
> = {}) => {
- return useMutation(
- (vars) => sendMagicLink(vars),
- {
- async onSuccess(data, variables, context) {
- // [Joshen] If we need to invalidate any queries
- await onSuccess?.(data, variables, context)
- },
- async onError(data, variables, context) {
- if (onError === undefined) {
- toast.error(`Failed to send magic link: ${data.message}`)
- } else {
- onError(data, variables, context)
- }
- },
- ...options,
- }
- )
+ return useMutation({
+ mutationFn: (vars) => sendMagicLink(vars),
+ async onSuccess(data, variables, context) {
+ // [Joshen] If we need to invalidate any queries
+ await onSuccess?.(data, variables, context)
+ },
+ async onError(data, variables, context) {
+ if (onError === undefined) {
+ toast.error(`Failed to send magic link: ${data.message}`)
+ } else {
+ onError(data, variables, context)
+ }
+ },
+ ...options,
+ })
}
diff --git a/apps/studio/data/auth/user-send-otp-mutation.ts b/apps/studio/data/auth/user-send-otp-mutation.ts
index 1ba5d3239fe6e..6072fcb969c22 100644
--- a/apps/studio/data/auth/user-send-otp-mutation.ts
+++ b/apps/studio/data/auth/user-send-otp-mutation.ts
@@ -31,21 +31,19 @@ export const useUserSendOTPMutation = ({
UseMutationOptions,
'mutationFn'
> = {}) => {
- return useMutation(
- (vars) => sendOTP(vars),
- {
- async onSuccess(data, variables, context) {
- // [Joshen] If we need to invalidate any queries
- await onSuccess?.(data, variables, context)
- },
- async onError(data, variables, context) {
- if (onError === undefined) {
- toast.error(`Failed to send magic link: ${data.message}`)
- } else {
- onError(data, variables, context)
- }
- },
- ...options,
- }
- )
+ return useMutation({
+ mutationFn: (vars) => sendOTP(vars),
+ async onSuccess(data, variables, context) {
+ // [Joshen] If we need to invalidate any queries
+ await onSuccess?.(data, variables, context)
+ },
+ async onError(data, variables, context) {
+ if (onError === undefined) {
+ toast.error(`Failed to send magic link: ${data.message}`)
+ } else {
+ onError(data, variables, context)
+ }
+ },
+ ...options,
+ })
}
diff --git a/apps/studio/data/auth/user-update-mutation.ts b/apps/studio/data/auth/user-update-mutation.ts
index 19cf3ae3b9f67..01209b201256c 100644
--- a/apps/studio/data/auth/user-update-mutation.ts
+++ b/apps/studio/data/auth/user-update-mutation.ts
@@ -34,22 +34,20 @@ export const useUserUpdateMutation = ({
> = {}) => {
const queryClient = useQueryClient()
- return useMutation(
- (vars) => updateUser(vars),
- {
- async onSuccess(data, variables, context) {
- const { projectRef } = variables
- await queryClient.invalidateQueries(authKeys.usersInfinite(projectRef))
- await onSuccess?.(data, variables, context)
- },
- async onError(data, variables, context) {
- if (onError === undefined) {
- toast.error(`Failed to update user: ${data.message}`)
- } else {
- onError(data, variables, context)
- }
- },
- ...options,
- }
- )
+ return useMutation({
+ mutationFn: (vars) => updateUser(vars),
+ async onSuccess(data, variables, context) {
+ const { projectRef } = variables
+ await queryClient.invalidateQueries(authKeys.usersInfinite(projectRef))
+ await onSuccess?.(data, variables, context)
+ },
+ async onError(data, variables, context) {
+ if (onError === undefined) {
+ toast.error(`Failed to update user: ${data.message}`)
+ } else {
+ onError(data, variables, context)
+ }
+ },
+ ...options,
+ })
}
diff --git a/apps/studio/data/auth/users-count-query.ts b/apps/studio/data/auth/users-count-query.ts
index 9c8730eff1013..67052362022e3 100644
--- a/apps/studio/data/auth/users-count-query.ts
+++ b/apps/studio/data/auth/users-count-query.ts
@@ -65,14 +65,14 @@ export const useUsersCountQuery = (
}: UsersCountVariables,
{ enabled = true, ...options }: UseQueryOptions = {}
) =>
- useQuery(
- authKeys.usersCount(projectRef, {
+ useQuery({
+ queryKey: authKeys.usersCount(projectRef, {
keywords,
filter,
providers,
forceExactCount,
}),
- ({ signal }) =>
+ queryFn: ({ signal }) =>
getUsersCount(
{
projectRef,
@@ -84,8 +84,6 @@ export const useUsersCountQuery = (
},
signal
),
- {
- enabled: enabled && typeof projectRef !== 'undefined',
- ...options,
- }
- )
+ enabled: enabled && typeof projectRef !== 'undefined',
+ ...options,
+ })
diff --git a/apps/studio/data/auth/validate-spam-mutation.ts b/apps/studio/data/auth/validate-spam-mutation.ts
index 78a46ac777d13..920a025f7d735 100644
--- a/apps/studio/data/auth/validate-spam-mutation.ts
+++ b/apps/studio/data/auth/validate-spam-mutation.ts
@@ -32,20 +32,18 @@ export const useValidateSpamMutation = ({
UseMutationOptions,
'mutationFn'
> = {}) => {
- return useMutation(
- (vars) => validateSpam(vars),
- {
- async onSuccess(data, variables, context) {
- await onSuccess?.(data, variables, context)
- },
- async onError(data, variables, context) {
- if (onError === undefined) {
- toast.error(`Failed to validate template: ${data.message}`)
- } else {
- onError(data, variables, context)
- }
- },
- ...options,
- }
- )
+ return useMutation({
+ mutationFn: (vars) => validateSpam(vars),
+ async onSuccess(data, variables, context) {
+ await onSuccess?.(data, variables, context)
+ },
+ async onError(data, variables, context) {
+ if (onError === undefined) {
+ toast.error(`Failed to validate template: ${data.message}`)
+ } else {
+ onError(data, variables, context)
+ }
+ },
+ ...options,
+ })
}
diff --git a/apps/studio/data/banned-ips/banned-ips-delete-mutations.ts b/apps/studio/data/banned-ips/banned-ips-delete-mutations.ts
index dc0a462fc9994..3fff21f34bafa 100644
--- a/apps/studio/data/banned-ips/banned-ips-delete-mutations.ts
+++ b/apps/studio/data/banned-ips/banned-ips-delete-mutations.ts
@@ -31,24 +31,22 @@ export const useBannedIPsDeleteMutation = ({
...options
}: Omit, 'mutationFn'> = {}) => {
const queryClient = useQueryClient()
- return useMutation(
- (vars) => deleteBannedIPs(vars),
- {
- async onSuccess(data, variables, context) {
- const { projectRef } = variables
-
- await queryClient.invalidateQueries(BannedIPKeys.list(projectRef))
-
- await onSuccess?.(data, variables, context)
- },
- async onError(data, variables, context) {
- if (onError === undefined) {
- toast.error(`Failed to unban ips: ${data.message}`)
- } else {
- onError(data, variables, context)
- }
- },
- ...options,
- }
- )
+ return useMutation({
+ mutationFn: (vars) => deleteBannedIPs(vars),
+ async onSuccess(data, variables, context) {
+ const { projectRef } = variables
+
+ await queryClient.invalidateQueries(BannedIPKeys.list(projectRef))
+
+ await onSuccess?.(data, variables, context)
+ },
+ async onError(data, variables, context) {
+ if (onError === undefined) {
+ toast.error(`Failed to unban ips: ${data.message}`)
+ } else {
+ onError(data, variables, context)
+ }
+ },
+ ...options,
+ })
}
diff --git a/apps/studio/data/banned-ips/banned-ips-query.ts b/apps/studio/data/banned-ips/banned-ips-query.ts
index 89964f6047774..710b68c3fb03b 100644
--- a/apps/studio/data/banned-ips/banned-ips-query.ts
+++ b/apps/studio/data/banned-ips/banned-ips-query.ts
@@ -30,11 +30,9 @@ export const useBannedIPsQuery = (
{ projectRef }: BannedIPVariables,
{ enabled = true, ...options }: UseQueryOptions = {}
) =>
- useQuery(
- BannedIPKeys.list(projectRef),
- ({ signal }) => getBannedIPs({ projectRef }, signal),
- {
- enabled: enabled && typeof projectRef !== 'undefined',
- ...options,
- }
- )
+ useQuery({
+ queryKey: BannedIPKeys.list(projectRef),
+ queryFn: ({ signal }) => getBannedIPs({ projectRef }, signal),
+ enabled: enabled && typeof projectRef !== 'undefined',
+ ...options,
+ })
diff --git a/apps/studio/data/branches/branch-create-mutation.ts b/apps/studio/data/branches/branch-create-mutation.ts
index 2b338ea056077..08d426c1f20af 100644
--- a/apps/studio/data/branches/branch-create-mutation.ts
+++ b/apps/studio/data/branches/branch-create-mutation.ts
@@ -52,22 +52,20 @@ export const useBranchCreateMutation = ({
'mutationFn'
> = {}) => {
const queryClient = useQueryClient()
- return useMutation(
- (vars) => createBranch(vars),
- {
- async onSuccess(data, variables, context) {
- const { projectRef } = variables
- await queryClient.invalidateQueries(branchKeys.list(projectRef))
- await onSuccess?.(data, variables, context)
- },
- async onError(data, variables, context) {
- if (onError === undefined) {
- toast.error(`Failed to create branch: ${data.message}`)
- } else {
- onError(data, variables, context)
- }
- },
- ...options,
- }
- )
+ return useMutation({
+ mutationFn: (vars) => createBranch(vars),
+ async onSuccess(data, variables, context) {
+ const { projectRef } = variables
+ await queryClient.invalidateQueries(branchKeys.list(projectRef))
+ await onSuccess?.(data, variables, context)
+ },
+ async onError(data, variables, context) {
+ if (onError === undefined) {
+ toast.error(`Failed to create branch: ${data.message}`)
+ } else {
+ onError(data, variables, context)
+ }
+ },
+ ...options,
+ })
}
diff --git a/apps/studio/data/branches/branch-delete-mutation.ts b/apps/studio/data/branches/branch-delete-mutation.ts
index fe0adb6d8d38e..1b9ca55e56e86 100644
--- a/apps/studio/data/branches/branch-delete-mutation.ts
+++ b/apps/studio/data/branches/branch-delete-mutation.ts
@@ -31,33 +31,31 @@ export const useBranchDeleteMutation = ({
'mutationFn'
> = {}) => {
const queryClient = useQueryClient()
- return useMutation(
- (vars) => deleteBranch(vars),
- {
- async onSuccess(data, variables, context) {
- const { branchRef, projectRef } = variables
- setTimeout(() => {
- queryClient.invalidateQueries(branchKeys.list(projectRef))
- }, 5000)
-
- const branches: BranchesData | undefined = queryClient.getQueryData(
- branchKeys.list(projectRef)
- )
- if (branches) {
- const updatedBranches = branches.filter((branch) => branch.project_ref !== branchRef)
- queryClient.setQueryData(branchKeys.list(projectRef), updatedBranches)
- }
-
- await onSuccess?.(data, variables, context)
- },
- async onError(data, variables, context) {
- if (onError === undefined) {
- toast.error(`Failed to delete branch: ${data.message}`)
- } else {
- onError(data, variables, context)
- }
- },
- ...options,
- }
- )
+ return useMutation({
+ mutationFn: (vars) => deleteBranch(vars),
+ async onSuccess(data, variables, context) {
+ const { branchRef, projectRef } = variables
+ setTimeout(() => {
+ queryClient.invalidateQueries(branchKeys.list(projectRef))
+ }, 5000)
+
+ const branches: BranchesData | undefined = queryClient.getQueryData(
+ branchKeys.list(projectRef)
+ )
+ if (branches) {
+ const updatedBranches = branches.filter((branch) => branch.project_ref !== branchRef)
+ queryClient.setQueryData(branchKeys.list(projectRef), updatedBranches)
+ }
+
+ await onSuccess?.(data, variables, context)
+ },
+ async onError(data, variables, context) {
+ if (onError === undefined) {
+ toast.error(`Failed to delete branch: ${data.message}`)
+ } else {
+ onError(data, variables, context)
+ }
+ },
+ ...options,
+ })
}
diff --git a/apps/studio/data/branches/branch-diff-query.ts b/apps/studio/data/branches/branch-diff-query.ts
index bdc83572fee3e..a3976d63a6590 100644
--- a/apps/studio/data/branches/branch-diff-query.ts
+++ b/apps/studio/data/branches/branch-diff-query.ts
@@ -47,11 +47,9 @@ export const useBranchDiffQuery = (
...options
}: Omit, 'queryKey' | 'queryFn'> = {}
) =>
- useQuery(
- branchKeys.diff(projectRef, branchRef),
- () => getBranchDiff({ branchRef, includedSchemas }),
- {
- enabled: IS_PLATFORM && enabled && Boolean(branchRef),
- ...options,
- }
- )
+ useQuery({
+ queryKey: branchKeys.diff(projectRef, branchRef),
+ queryFn: () => getBranchDiff({ branchRef, includedSchemas }),
+ enabled: IS_PLATFORM && enabled && Boolean(branchRef),
+ ...options,
+ })
diff --git a/apps/studio/data/branches/branch-merge-mutation.ts b/apps/studio/data/branches/branch-merge-mutation.ts
index b6a1fd5691819..9c2c8bf24d70f 100644
--- a/apps/studio/data/branches/branch-merge-mutation.ts
+++ b/apps/studio/data/branches/branch-merge-mutation.ts
@@ -63,24 +63,22 @@ export const useBranchMergeMutation = ({
'mutationFn'
> = {}) => {
const queryClient = useQueryClient()
- return useMutation(
- (vars) => mergeBranch(vars),
- {
- async onSuccess(data, variables, context) {
- const { baseProjectRef } = variables
- await queryClient.invalidateQueries(branchKeys.list(baseProjectRef))
- await onSuccess?.(data, variables, context)
- },
- async onError(data, variables, context) {
- if (onError === undefined) {
- let errorMessage = data.message || 'Unknown error occurred'
+ return useMutation({
+ mutationFn: (vars) => mergeBranch(vars),
+ async onSuccess(data, variables, context) {
+ const { baseProjectRef } = variables
+ await queryClient.invalidateQueries(branchKeys.list(baseProjectRef))
+ await onSuccess?.(data, variables, context)
+ },
+ async onError(data, variables, context) {
+ if (onError === undefined) {
+ let errorMessage = data.message || 'Unknown error occurred'
- toast.error(`Failed to merge branch: ${errorMessage}`)
- } else {
- onError(data, variables, context)
- }
- },
- ...options,
- }
- )
+ toast.error(`Failed to merge branch: ${errorMessage}`)
+ } else {
+ onError(data, variables, context)
+ }
+ },
+ ...options,
+ })
}
diff --git a/apps/studio/data/branches/branch-push-mutation.ts b/apps/studio/data/branches/branch-push-mutation.ts
index 1ffb4ac909a80..3b36d83ff0a6e 100644
--- a/apps/studio/data/branches/branch-push-mutation.ts
+++ b/apps/studio/data/branches/branch-push-mutation.ts
@@ -31,22 +31,20 @@ export const useBranchPushMutation = ({
'mutationFn'
> = {}) => {
const queryClient = useQueryClient()
- return useMutation(
- (vars) => pushBranch(vars),
- {
- async onSuccess(data, variables, context) {
- const { projectRef } = variables
- await queryClient.invalidateQueries(branchKeys.list(projectRef))
- await onSuccess?.(data, variables, context)
- },
- async onError(data, variables, context) {
- if (onError === undefined) {
- toast.error(`Failed to push branch: ${data.message}`)
- } else {
- onError(data, variables, context)
- }
- },
- ...options,
- }
- )
+ return useMutation({
+ mutationFn: (vars) => pushBranch(vars),
+ async onSuccess(data, variables, context) {
+ const { projectRef } = variables
+ await queryClient.invalidateQueries(branchKeys.list(projectRef))
+ await onSuccess?.(data, variables, context)
+ },
+ async onError(data, variables, context) {
+ if (onError === undefined) {
+ toast.error(`Failed to push branch: ${data.message}`)
+ } else {
+ onError(data, variables, context)
+ }
+ },
+ ...options,
+ })
}
diff --git a/apps/studio/data/branches/branch-query.ts b/apps/studio/data/branches/branch-query.ts
index 81fee2ba79bf7..03c83a3e88f60 100644
--- a/apps/studio/data/branches/branch-query.ts
+++ b/apps/studio/data/branches/branch-query.ts
@@ -29,11 +29,9 @@ export const useBranchQuery = (
{ projectRef, branchRef }: BranchVariables,
{ enabled = true, ...options }: UseQueryOptions = {}
) =>
- useQuery(
- branchKeys.detail(projectRef, branchRef),
- ({ signal }) => getBranch({ branchRef }, signal),
- {
- enabled: IS_PLATFORM && enabled && Boolean(branchRef),
- ...options,
- }
- )
+ useQuery({
+ queryKey: branchKeys.detail(projectRef, branchRef),
+ queryFn: ({ signal }) => getBranch({ branchRef }, signal),
+ enabled: IS_PLATFORM && enabled && Boolean(branchRef),
+ ...options,
+ })
diff --git a/apps/studio/data/branches/branch-reset-mutation.ts b/apps/studio/data/branches/branch-reset-mutation.ts
index f54e61a35c6a5..fd2b21f6a6be8 100644
--- a/apps/studio/data/branches/branch-reset-mutation.ts
+++ b/apps/studio/data/branches/branch-reset-mutation.ts
@@ -31,22 +31,20 @@ export const useBranchResetMutation = ({
'mutationFn'
> = {}) => {
const queryClient = useQueryClient()
- return useMutation(
- (vars) => resetBranch(vars),
- {
- async onSuccess(data, variables, context) {
- const { projectRef } = variables
- await queryClient.invalidateQueries(branchKeys.list(projectRef))
- await onSuccess?.(data, variables, context)
- },
- async onError(data, variables, context) {
- if (onError === undefined) {
- toast.error(`Failed to reset branch: ${data.message}`)
- } else {
- onError(data, variables, context)
- }
- },
- ...options,
- }
- )
+ return useMutation({
+ mutationFn: (vars) => resetBranch(vars),
+ async onSuccess(data, variables, context) {
+ const { projectRef } = variables
+ await queryClient.invalidateQueries(branchKeys.list(projectRef))
+ await onSuccess?.(data, variables, context)
+ },
+ async onError(data, variables, context) {
+ if (onError === undefined) {
+ toast.error(`Failed to reset branch: ${data.message}`)
+ } else {
+ onError(data, variables, context)
+ }
+ },
+ ...options,
+ })
}
diff --git a/apps/studio/data/branches/branch-update-mutation.ts b/apps/studio/data/branches/branch-update-mutation.ts
index 2ea12830fd08b..f8233395ba9b6 100644
--- a/apps/studio/data/branches/branch-update-mutation.ts
+++ b/apps/studio/data/branches/branch-update-mutation.ts
@@ -48,22 +48,20 @@ export const useBranchUpdateMutation = ({
'mutationFn'
> = {}) => {
const queryClient = useQueryClient()
- return useMutation(
- (vars) => updateBranch(vars),
- {
- async onSuccess(data, variables, context) {
- const { projectRef } = variables
- await queryClient.invalidateQueries(branchKeys.list(projectRef))
- await onSuccess?.(data, variables, context)
- },
- async onError(data, variables, context) {
- if (onError === undefined) {
- toast.error(`Failed to update branch: ${data.message}`)
- } else {
- onError(data, variables, context)
- }
- },
- ...options,
- }
- )
+ return useMutation({
+ mutationFn: (vars) => updateBranch(vars),
+ async onSuccess(data, variables, context) {
+ const { projectRef } = variables
+ await queryClient.invalidateQueries(branchKeys.list(projectRef))
+ await onSuccess?.(data, variables, context)
+ },
+ async onError(data, variables, context) {
+ if (onError === undefined) {
+ toast.error(`Failed to update branch: ${data.message}`)
+ } else {
+ onError(data, variables, context)
+ }
+ },
+ ...options,
+ })
}
diff --git a/apps/studio/data/branches/branches-query.ts b/apps/studio/data/branches/branches-query.ts
index 69aad2f835a90..cf4f95f4b1720 100644
--- a/apps/studio/data/branches/branches-query.ts
+++ b/apps/studio/data/branches/branches-query.ts
@@ -38,8 +38,9 @@ export const useBranchesQuery = (
{ projectRef }: BranchesVariables,
{ enabled = true, ...options }: UseQueryOptions = {}
) =>
- useQuery(
- branchKeys.list(projectRef),
- ({ signal }) => getBranches({ projectRef }, signal),
- { enabled: IS_PLATFORM && enabled && Boolean(projectRef), ...options }
- )
+ useQuery({
+ queryKey: branchKeys.list(projectRef),
+ queryFn: ({ signal }) => getBranches({ projectRef }, signal),
+ enabled: IS_PLATFORM && enabled && Boolean(projectRef),
+ ...options,
+ })
diff --git a/apps/studio/data/config/disk-attributes-query.ts b/apps/studio/data/config/disk-attributes-query.ts
index 84c55f721cf6b..eb5f49cb59ef4 100644
--- a/apps/studio/data/config/disk-attributes-query.ts
+++ b/apps/studio/data/config/disk-attributes-query.ts
@@ -39,11 +39,12 @@ export const useDiskAttributesQuery = (
...options
}: UseQueryOptions = {}
) =>
- useQuery(
- configKeys.diskAttributes(projectRef),
- ({ signal }) => getDiskAttributes({ projectRef }, signal),
- { enabled: enabled && typeof projectRef !== 'undefined', ...options }
- )
+ useQuery({
+ queryKey: configKeys.diskAttributes(projectRef),
+ queryFn: ({ signal }) => getDiskAttributes({ projectRef }, signal),
+ enabled: enabled && typeof projectRef !== 'undefined',
+ ...options,
+ })
export const useRemainingDurationForDiskAttributeUpdate = ({
projectRef,
diff --git a/apps/studio/data/config/disk-attributes-update-mutation.ts b/apps/studio/data/config/disk-attributes-update-mutation.ts
index 8a289448f3a78..e50d3dbec245a 100644
--- a/apps/studio/data/config/disk-attributes-update-mutation.ts
+++ b/apps/studio/data/config/disk-attributes-update-mutation.ts
@@ -54,22 +54,20 @@ export const useUpdateDiskAttributesMutation = ({
'mutationFn'
> = {}) => {
const queryClient = useQueryClient()
- return useMutation(
- (vars) => updateDiskAttributes(vars),
- {
- async onSuccess(data, variables, context) {
- const { ref } = variables
- await queryClient.invalidateQueries(configKeys.diskAttributes(ref))
- await onSuccess?.(data, variables, context)
- },
- async onError(data, variables, context) {
- if (onError === undefined) {
- toast.error(`Failed to update disk attributes: ${data.message}`)
- } else {
- onError(data, variables, context)
- }
- },
- ...options,
- }
- )
+ return useMutation({
+ mutationFn: (vars) => updateDiskAttributes(vars),
+ async onSuccess(data, variables, context) {
+ const { ref } = variables
+ await queryClient.invalidateQueries(configKeys.diskAttributes(ref))
+ await onSuccess?.(data, variables, context)
+ },
+ async onError(data, variables, context) {
+ if (onError === undefined) {
+ toast.error(`Failed to update disk attributes: ${data.message}`)
+ } else {
+ onError(data, variables, context)
+ }
+ },
+ ...options,
+ })
}
diff --git a/apps/studio/data/config/disk-autoscale-config-query.ts b/apps/studio/data/config/disk-autoscale-config-query.ts
index bde9263c2fc13..6d44f7f8b0bac 100644
--- a/apps/studio/data/config/disk-autoscale-config-query.ts
+++ b/apps/studio/data/config/disk-autoscale-config-query.ts
@@ -35,8 +35,9 @@ export const useDiskAutoscaleCustomConfigQuery = = {}
) =>
- useQuery(
- configKeys.diskAutoscaleConfig(projectRef),
- ({ signal }) => getDiskAutoscaleCustomConfig({ projectRef }, signal),
- { enabled: enabled && typeof projectRef !== 'undefined', ...options }
- )
+ useQuery({
+ queryKey: configKeys.diskAutoscaleConfig(projectRef),
+ queryFn: ({ signal }) => getDiskAutoscaleCustomConfig({ projectRef }, signal),
+ enabled: enabled && typeof projectRef !== 'undefined',
+ ...options,
+ })
diff --git a/apps/studio/data/config/disk-autoscale-config-update-mutation.ts b/apps/studio/data/config/disk-autoscale-config-update-mutation.ts
index e9c37ceb744ba..6da6272a27942 100644
--- a/apps/studio/data/config/disk-autoscale-config-update-mutation.ts
+++ b/apps/studio/data/config/disk-autoscale-config-update-mutation.ts
@@ -53,7 +53,8 @@ export const useUpdateDiskAutoscaleConfigMutation = ({
UpdateDiskAutoscaleConfigData,
ResponseError,
UpdateDiskAutoscaleConfigVariables
- >((vars) => updateDiskAutoscaleConfig(vars), {
+ >({
+ mutationFn: (vars) => updateDiskAutoscaleConfig(vars),
async onSuccess(data, variables, context) {
const { projectRef } = variables
await queryClient.invalidateQueries(configKeys.diskAutoscaleConfig(projectRef))
diff --git a/apps/studio/data/config/disk-breakdown-query.ts b/apps/studio/data/config/disk-breakdown-query.ts
index 5f5f42c5ce97e..757a289735cca 100644
--- a/apps/studio/data/config/disk-breakdown-query.ts
+++ b/apps/studio/data/config/disk-breakdown-query.ts
@@ -52,8 +52,9 @@ export const useDiskBreakdownQuery = (
{ projectRef, connectionString }: DiskBreakdownVariables,
{ enabled = true, ...options }: UseQueryOptions = {}
) =>
- useQuery(
- configKeys.diskBreakdown(projectRef),
- ({ signal }) => getDiskBreakdown({ projectRef, connectionString }, signal),
- { enabled: enabled && typeof projectRef !== 'undefined', ...options }
- )
+ useQuery({
+ queryKey: configKeys.diskBreakdown(projectRef),
+ queryFn: ({ signal }) => getDiskBreakdown({ projectRef, connectionString }, signal),
+ enabled: enabled && typeof projectRef !== 'undefined',
+ ...options,
+ })
diff --git a/apps/studio/data/config/disk-utilization-query.ts b/apps/studio/data/config/disk-utilization-query.ts
index 5d8b786f3e8d3..3e7a5f394f00e 100644
--- a/apps/studio/data/config/disk-utilization-query.ts
+++ b/apps/studio/data/config/disk-utilization-query.ts
@@ -33,8 +33,9 @@ export const useDiskUtilizationQuery = (
...options
}: UseQueryOptions = {}
) =>
- useQuery(
- configKeys.diskUtilization(projectRef),
- ({ signal }) => getDiskUtilization({ projectRef }, signal),
- { enabled: enabled && typeof projectRef !== 'undefined', ...options }
- )
+ useQuery