mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 09:25:06 +03:00
Replace ui setnotification with toast part 2 (#21872)
* Replace ui setnotification with toast part 2 * Prettier lint
This commit is contained in:
1 parent
827b01c37a
commit
540049992d
50 files changed
+388
-706
No files matched your search
@@ -1,23 +1,23 @@
|
||||
import { PermissionAction } from '@supabase/shared-types/out/constants'
|
||||
import { useParams } from 'common'
|
||||
import { codeBlock } from 'common-tags'
|
||||
import { PropsWithChildren, useMemo } from 'react'
|
||||
import toast from 'react-hot-toast'
|
||||
import { CommandMenuProvider } from 'ui'
|
||||
|
||||
import { codeBlock } from 'common-tags'
|
||||
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import { useProjectApiQuery } from 'data/config/project-api-query'
|
||||
import type { SqlSnippet } from 'data/content/sql-snippets-query'
|
||||
import { useEntityDefinitionsQuery } from 'data/database/entity-definitions-query'
|
||||
import { useCheckPermissions, useSelectedOrganization, useStore } from 'hooks'
|
||||
import { useCheckPermissions, useSelectedOrganization } from 'hooks'
|
||||
import { OPT_IN_TAGS } from 'lib/constants'
|
||||
import { uuidv4 } from 'lib/helpers'
|
||||
import { useProfile } from 'lib/profile'
|
||||
import { useSqlEditorStateSnapshot } from 'state/sql-editor'
|
||||
import { createSqlSnippetSkeleton } from '../SQLEditor/SQLEditor.utils'
|
||||
import { OPT_IN_TAGS } from 'lib/constants'
|
||||
|
||||
const CommandMenuWrapper = ({ children }: PropsWithChildren<{}>) => {
|
||||
const { ref } = useParams()
|
||||
const { ui } = useStore()
|
||||
const selectedOrganization = useSelectedOrganization()
|
||||
const { project: selectedProject } = useProjectContext()
|
||||
const opt_in_tags = selectedOrganization?.opt_in_tags
|
||||
@@ -56,10 +56,7 @@ const CommandMenuWrapper = ({ children }: PropsWithChildren<{}>) => {
|
||||
const onSaveGeneratedSQL = async (answer: string, title: string) => {
|
||||
if (!ref) return console.error('Project ref is required')
|
||||
if (!canCreateSQLSnippet) {
|
||||
ui.setNotification({
|
||||
category: 'info',
|
||||
message: 'Unable to save query as you do not have sufficient permissions for this project',
|
||||
})
|
||||
toast('Unable to save query as you do not have sufficient permissions for this project')
|
||||
return
|
||||
}
|
||||
|
||||
@@ -84,15 +81,9 @@ const CommandMenuWrapper = ({ children }: PropsWithChildren<{}>) => {
|
||||
})
|
||||
|
||||
snap.addSnippet(snippet as SqlSnippet, ref)
|
||||
ui.setNotification({
|
||||
category: 'success',
|
||||
message: `Successfully saved snippet!`,
|
||||
})
|
||||
toast.success(`Successfully saved snippet!`)
|
||||
} catch (error: any) {
|
||||
ui.setNotification({
|
||||
category: 'error',
|
||||
message: `Failed to create new query: ${error.message}`,
|
||||
})
|
||||
toast.error(`Failed to create new query: ${error.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
import { observer } from 'mobx-react-lite'
|
||||
import { useRouter } from 'next/router'
|
||||
import { PropsWithChildren, useEffect } from 'react'
|
||||
import toast from 'react-hot-toast'
|
||||
|
||||
import { useIsLoggedIn, useParams } from 'common'
|
||||
import { useOrganizationsQuery } from 'data/organizations/organizations-query'
|
||||
import { useProjectsQuery } from 'data/projects/projects-query'
|
||||
import { useFlag, useStore, useLatest } from 'hooks'
|
||||
import { useFlag, useLatest } from 'hooks'
|
||||
import { DEFAULT_HOME, IS_PLATFORM, LOCAL_STORAGE_KEYS } from 'lib/constants'
|
||||
import { useAppStateSnapshot } from 'state/app-state'
|
||||
|
||||
// Ideally these could all be within a _middleware when we use Next 12
|
||||
const RouteValidationWrapper = ({ children }: PropsWithChildren<{}>) => {
|
||||
const { ui } = useStore()
|
||||
const router = useRouter()
|
||||
const { ref, slug, id } = useParams()
|
||||
const navLayoutV2 = useFlag('navigationLayoutV2')
|
||||
@@ -55,7 +55,7 @@ const RouteValidationWrapper = ({ children }: PropsWithChildren<{}>) => {
|
||||
const isValidOrg = organizations.some((org) => org.slug === slug)
|
||||
|
||||
if (!isValidOrg) {
|
||||
ui.setNotification({ category: 'error', message: 'This organization does not exist' })
|
||||
toast.error('This organization does not exist')
|
||||
router.push(navLayoutV2 ? `/org/${organizations[0].slug}` : DEFAULT_HOME)
|
||||
return
|
||||
}
|
||||
@@ -80,7 +80,7 @@ const RouteValidationWrapper = ({ children }: PropsWithChildren<{}>) => {
|
||||
: true
|
||||
|
||||
if (!isValidProject && !isValidBranch) {
|
||||
ui.setNotification({ category: 'error', message: 'This project does not exist' })
|
||||
toast.error('This project does not exist')
|
||||
router.push(navLayoutV2 ? `/org/${organizations?.[0].slug}` : DEFAULT_HOME)
|
||||
return
|
||||
}
|
||||
|
||||
+4
-10
@@ -1,6 +1,7 @@
|
||||
import { PermissionAction } from '@supabase/shared-types/out/constants'
|
||||
import { useParams } from 'common'
|
||||
import { useEffect, useState } from 'react'
|
||||
import toast from 'react-hot-toast'
|
||||
import {
|
||||
AlertDescription_Shadcn_,
|
||||
AlertTitle_Shadcn_,
|
||||
@@ -28,7 +29,7 @@ import UpgradeToPro from 'components/ui/UpgradeToPro'
|
||||
import { useAuthConfigQuery } from 'data/auth/auth-config-query'
|
||||
import { useAuthConfigUpdateMutation } from 'data/auth/auth-config-update-mutation'
|
||||
import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query'
|
||||
import { useCheckPermissions, useSelectedOrganization, useStore } from 'hooks'
|
||||
import { useCheckPermissions, useSelectedOrganization } from 'hooks'
|
||||
import { IS_PLATFORM } from 'lib/constants'
|
||||
import FormField from '../AuthProvidersForm/FormField'
|
||||
|
||||
@@ -74,7 +75,6 @@ function HoursOrNeverText({ value }: { value: number }) {
|
||||
const formId = 'auth-config-basic-settings'
|
||||
|
||||
const BasicAuthSettingsForm = () => {
|
||||
const { ui } = useStore()
|
||||
const { ref: projectRef } = useParams()
|
||||
const {
|
||||
data: authConfig,
|
||||
@@ -127,16 +127,10 @@ const BasicAuthSettingsForm = () => {
|
||||
{ projectRef: projectRef!, config: payload },
|
||||
{
|
||||
onError: (error) => {
|
||||
ui.setNotification({
|
||||
category: 'error',
|
||||
message: `Failed to update settings: ${error?.message}`,
|
||||
})
|
||||
toast.error(`Failed to update settings: ${error?.message}`)
|
||||
},
|
||||
onSuccess: () => {
|
||||
ui.setNotification({
|
||||
category: 'success',
|
||||
message: `Successfully updated settings`,
|
||||
})
|
||||
toast.success(`Successfully updated settings`)
|
||||
resetForm({ values: values, initialValues: values })
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { PermissionAction } from '@supabase/shared-types/out/constants'
|
||||
import { useParams } from 'common'
|
||||
import { useEffect } from 'react'
|
||||
import toast from 'react-hot-toast'
|
||||
import {
|
||||
AlertDescription_Shadcn_,
|
||||
AlertTitle_Shadcn_,
|
||||
@@ -23,7 +24,7 @@ import UpgradeToPro from 'components/ui/UpgradeToPro'
|
||||
import { useAuthConfigQuery } from 'data/auth/auth-config-query'
|
||||
import { useAuthConfigUpdateMutation } from 'data/auth/auth-config-update-mutation'
|
||||
import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query'
|
||||
import { useCheckPermissions, useSelectedOrganization, useStore } from 'hooks'
|
||||
import { useCheckPermissions, useSelectedOrganization } from 'hooks'
|
||||
import SchemaFunctionSelector from './SchemaFunctionSelector'
|
||||
|
||||
const schema = object({
|
||||
@@ -36,7 +37,6 @@ const schema = object({
|
||||
const FORM_ID = 'enterprise-hooks-config'
|
||||
|
||||
const EnterpriseHooksConfig = () => {
|
||||
const { ui } = useStore()
|
||||
const { ref: projectRef } = useParams()
|
||||
const {
|
||||
data: authConfig,
|
||||
@@ -79,16 +79,10 @@ const EnterpriseHooksConfig = () => {
|
||||
{ projectRef: projectRef!, config: payload },
|
||||
{
|
||||
onError: () => {
|
||||
ui.setNotification({
|
||||
category: 'error',
|
||||
message: `Failed to update settings`,
|
||||
})
|
||||
toast.error(`Failed to update settings`)
|
||||
},
|
||||
onSuccess: () => {
|
||||
ui.setNotification({
|
||||
category: 'success',
|
||||
message: `Successfully updated settings`,
|
||||
})
|
||||
toast.success(`Successfully updated settings`)
|
||||
resetForm({ values: values, initialValues: values })
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { isEmpty, noop } from 'lodash'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { Modal } from 'ui'
|
||||
import toast from 'react-hot-toast'
|
||||
|
||||
import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal'
|
||||
import { useStore } from 'hooks'
|
||||
import { LOCAL_STORAGE_KEYS } from 'lib/constants'
|
||||
import { useAppStateSnapshot } from 'state/app-state'
|
||||
import { Modal } from 'ui'
|
||||
import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal'
|
||||
import { POLICY_MODAL_VIEWS } from '../Policies.constants'
|
||||
import {
|
||||
PolicyFormField,
|
||||
@@ -48,7 +48,6 @@ const PolicyEditorModal = ({
|
||||
onUpdatePolicy,
|
||||
onSaveSuccess = noop,
|
||||
}: PolicyEditorModalProps) => {
|
||||
const { ui } = useStore()
|
||||
const snap = useAppStateSnapshot()
|
||||
|
||||
const newPolicyTemplate: PolicyFormField = {
|
||||
@@ -124,36 +123,21 @@ const PolicyEditorModal = ({
|
||||
const { name, definition, check, command } = policyFormFields
|
||||
|
||||
if (name.length === 0) {
|
||||
return ui.setNotification({ category: 'error', message: 'Do give your policy a name' })
|
||||
return toast.error('Please provide a name for your policy')
|
||||
}
|
||||
if (!command) {
|
||||
return ui.setNotification({
|
||||
category: 'error',
|
||||
message: 'You will need to allow at one operation in your policy',
|
||||
duration: 4000,
|
||||
})
|
||||
return toast.error('Please select an operation for your policy')
|
||||
}
|
||||
if (['SELECT', 'DELETE'].includes(command) && !definition) {
|
||||
return ui.setNotification({
|
||||
category: 'error',
|
||||
message: 'Did you forget to provide a USING expression for your policy?',
|
||||
duration: 4000,
|
||||
})
|
||||
return toast.error('Please provide a USING expression for your policy')
|
||||
}
|
||||
if (command === 'INSERT' && !check) {
|
||||
return ui.setNotification({
|
||||
category: 'error',
|
||||
message: 'Did you forget to provide a WITH CHECK expression for your policy?',
|
||||
duration: 4000,
|
||||
})
|
||||
return toast.error('Please provide a WITH CHECK expression for your policy')
|
||||
}
|
||||
if (command === 'UPDATE' && !definition && !check) {
|
||||
return ui.setNotification({
|
||||
category: 'error',
|
||||
message:
|
||||
'You will need to provide either a USING, or WITH CHECK expression, or both for your policy',
|
||||
duration: 4000,
|
||||
})
|
||||
return toast.error(
|
||||
'Please provide either a USING, or WITH CHECK expression, or both for your policy'
|
||||
)
|
||||
}
|
||||
const policySQLStatement = createSQLPolicy(policyFormFields, selectedPolicyToEdit)
|
||||
setPolicyStatementForReview(policySQLStatement)
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
import * as Tooltip from '@radix-ui/react-tooltip'
|
||||
import { useParams } from 'common'
|
||||
import { useState } from 'react'
|
||||
import toast from 'react-hot-toast'
|
||||
|
||||
import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal'
|
||||
import { useUserDeleteMFAFactorsMutation } from 'data/auth/user-delete-mfa-factors-mutation'
|
||||
import { useUserDeleteMutation } from 'data/auth/user-delete-mutation'
|
||||
import { useUserResetPasswordMutation } from 'data/auth/user-reset-password-mutation'
|
||||
import { useUserSendMagicLinkMutation } from 'data/auth/user-send-magic-link-mutation'
|
||||
import { useUserSendOTPMutation } from 'data/auth/user-send-otp-mutation'
|
||||
import type { User } from 'data/auth/users-query'
|
||||
import { useStore } from 'hooks'
|
||||
import { timeout } from 'lib/helpers'
|
||||
import {
|
||||
Button,
|
||||
@@ -26,6 +25,7 @@ import {
|
||||
IconUser,
|
||||
Modal,
|
||||
} from 'ui'
|
||||
import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal'
|
||||
|
||||
interface UserDropdownProps {
|
||||
user: User
|
||||
@@ -42,31 +42,21 @@ const UserDropdown = ({
|
||||
setSelectedUser,
|
||||
setUserSidePanelOpen,
|
||||
}: UserDropdownProps) => {
|
||||
const { ui } = useStore()
|
||||
const { ref } = useParams()
|
||||
|
||||
const { mutate: resetPassword, isLoading: isResetting } = useUserResetPasswordMutation({
|
||||
onSuccess: () => {
|
||||
ui.setNotification({
|
||||
category: 'success',
|
||||
message: `Sent password recovery to ${user.email}`,
|
||||
})
|
||||
toast.success(`Sent password recovery to ${user.email}`)
|
||||
},
|
||||
})
|
||||
const { mutate: sendMagicLink, isLoading: isSendingLink } = useUserSendMagicLinkMutation({
|
||||
onSuccess: () => {
|
||||
ui.setNotification({
|
||||
category: 'success',
|
||||
message: `Sent magic link to ${user.email}`,
|
||||
})
|
||||
toast.success(`Sent magic link to ${user.email}`)
|
||||
},
|
||||
})
|
||||
const { mutate: sendOTP, isLoading: isSendingOTP } = useUserSendOTPMutation({
|
||||
onSuccess: () => {
|
||||
ui.setNotification({
|
||||
category: 'success',
|
||||
message: `Sent OTP to ${user.phone}`,
|
||||
})
|
||||
toast.success(`Sent OTP to ${user.phone}`)
|
||||
},
|
||||
})
|
||||
const { mutateAsync: deleteUser, isLoading: isDeleting } = useUserDeleteMutation()
|
||||
@@ -97,13 +87,10 @@ const UserDropdown = ({
|
||||
if (!ref) return console.error('Project ref is required')
|
||||
try {
|
||||
await deleteUser({ projectRef: ref, user })
|
||||
ui.setNotification({ category: 'success', message: `Successfully deleted ${user.email}` })
|
||||
toast.success(`Successfully deleted ${user.email}`)
|
||||
setIsDeleteModalOpen(false)
|
||||
} catch (error: any) {
|
||||
ui.setNotification({
|
||||
category: 'error',
|
||||
message: error?.message ?? 'Something went wrong while trying to delete user',
|
||||
})
|
||||
toast.error(error?.message ?? 'Something went wrong while trying to delete user')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,16 +104,10 @@ const UserDropdown = ({
|
||||
|
||||
try {
|
||||
await deleteUserMFAFactors({ projectRef: ref, userId: user.id })
|
||||
ui.setNotification({
|
||||
category: 'success',
|
||||
message: "Successfully deleted the user's factors",
|
||||
})
|
||||
toast.success("Successfully deleted the user's factors")
|
||||
setIsDeleteFactorsModalOpen(false)
|
||||
} catch (error: any) {
|
||||
ui.setNotification({
|
||||
category: 'error',
|
||||
message: error?.message ?? "Something went wrong while trying to delete user's factors",
|
||||
})
|
||||
toast.error(error?.message ?? "Something went wrong while trying to delete user's factors")
|
||||
} finally {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,16 @@ import { MessageCircle } from 'lucide-react'
|
||||
import Link from 'next/link'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useState } from 'react'
|
||||
import toast from 'react-hot-toast'
|
||||
|
||||
import { ScaffoldContainer, ScaffoldSection } from 'components/layouts/Scaffold'
|
||||
import AlertError from 'components/ui/AlertError'
|
||||
import { useBranchDeleteMutation } from 'data/branches/branch-delete-mutation'
|
||||
import { useBranchesDisableMutation } from 'data/branches/branches-disable-mutation'
|
||||
import { Branch, useBranchesQuery } from 'data/branches/branches-query'
|
||||
import { useGitHubConnectionsQuery } from 'data/integrations/github-connections-query'
|
||||
import { useGitHubPullRequestsQuery } from 'data/integrations/github-pull-requests-query'
|
||||
import { useSelectedOrganization, useSelectedProject } from 'hooks'
|
||||
import {
|
||||
AlertDescription_Shadcn_,
|
||||
AlertTitle_Shadcn_,
|
||||
@@ -16,15 +26,6 @@ import {
|
||||
} from 'ui'
|
||||
import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal'
|
||||
import TextConfirmModal from 'ui-patterns/Dialogs/TextConfirmModal'
|
||||
|
||||
import { ScaffoldContainer, ScaffoldSection } from 'components/layouts/Scaffold'
|
||||
import AlertError from 'components/ui/AlertError'
|
||||
import { useBranchDeleteMutation } from 'data/branches/branch-delete-mutation'
|
||||
import { useBranchesDisableMutation } from 'data/branches/branches-disable-mutation'
|
||||
import { Branch, useBranchesQuery } from 'data/branches/branches-query'
|
||||
import { useGitHubConnectionsQuery } from 'data/integrations/github-connections-query'
|
||||
import { useGitHubPullRequestsQuery } from 'data/integrations/github-pull-requests-query'
|
||||
import { useSelectedOrganization, useSelectedProject, useStore } from 'hooks'
|
||||
import { BranchLoader, BranchManagementSection, BranchRow } from './BranchPanels'
|
||||
import CreateBranchModal from './CreateBranchModal'
|
||||
import {
|
||||
@@ -35,7 +36,6 @@ import {
|
||||
import Overview from './Overview'
|
||||
|
||||
const BranchManagement = () => {
|
||||
const { ui } = useStore()
|
||||
const router = useRouter()
|
||||
const { ref } = useParams()
|
||||
const project = useSelectedProject()
|
||||
@@ -119,14 +119,12 @@ const BranchManagement = () => {
|
||||
const { mutate: deleteBranch, isLoading: isDeleting } = useBranchDeleteMutation({
|
||||
onSuccess: () => {
|
||||
if (selectedBranchToDelete?.project_ref === ref) {
|
||||
ui.setNotification({
|
||||
category: 'success',
|
||||
message:
|
||||
'Successfully deleted branch. You are now currently on the main branch of your project.',
|
||||
})
|
||||
toast.success(
|
||||
'Successfully deleted branch. You are now currently on the main branch of your project.'
|
||||
)
|
||||
router.push(`/project/${projectRef}/branches`)
|
||||
} else {
|
||||
ui.setNotification({ category: 'success', message: 'Successfully deleted branch' })
|
||||
toast.success('Successfully deleted branch')
|
||||
}
|
||||
setSelectedBranchToDelete(undefined)
|
||||
},
|
||||
@@ -134,10 +132,7 @@ const BranchManagement = () => {
|
||||
|
||||
const { mutate: disableBranching, isLoading: isDisabling } = useBranchesDisableMutation({
|
||||
onSuccess: () => {
|
||||
ui.setNotification({
|
||||
category: 'success',
|
||||
message: 'Successfully disabled branching for project',
|
||||
})
|
||||
toast.success('Successfully disabled branching for project')
|
||||
setShowDisableBranching(false)
|
||||
},
|
||||
})
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import type { PostgresTrigger } from '@supabase/postgres-meta'
|
||||
import toast from 'react-hot-toast'
|
||||
|
||||
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import TextConfirmModal from 'ui-patterns/Dialogs/TextConfirmModal'
|
||||
import { useDatabaseTriggerDeleteMutation } from 'data/database-triggers/database-trigger-delete-mutation'
|
||||
import { useStore } from 'hooks'
|
||||
|
||||
interface DeleteHookModalProps {
|
||||
visible: boolean
|
||||
@@ -12,14 +12,13 @@ interface DeleteHookModalProps {
|
||||
}
|
||||
|
||||
const DeleteHookModal = ({ selectedHook, visible, onClose }: DeleteHookModalProps) => {
|
||||
const { ui } = useStore()
|
||||
const { id, name, schema } = selectedHook ?? {}
|
||||
|
||||
const { project } = useProjectContext()
|
||||
const { mutate: deleteDatabaseTrigger, isLoading: isDeleting } = useDatabaseTriggerDeleteMutation(
|
||||
{
|
||||
onSuccess: () => {
|
||||
ui.setNotification({ category: 'success', message: `Successfully deleted ${name}` })
|
||||
toast.success(`Successfully deleted ${name}`)
|
||||
onClose()
|
||||
},
|
||||
}
|
||||
@@ -30,7 +29,7 @@ const DeleteHookModal = ({ selectedHook, visible, onClose }: DeleteHookModalProp
|
||||
return console.error('Project ref is required')
|
||||
}
|
||||
if (!id) {
|
||||
return ui.setNotification({ category: 'error', message: 'Unable find selected hook' })
|
||||
return toast.error('Unable find selected hook')
|
||||
}
|
||||
|
||||
deleteDatabaseTrigger({
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import type { PostgresTable, PostgresTrigger } from '@supabase/postgres-meta'
|
||||
import Image from 'next/legacy/image'
|
||||
import { MutableRefObject, useEffect, useMemo, useRef, useState } from 'react'
|
||||
import toast from 'react-hot-toast'
|
||||
|
||||
import { useParams } from 'common/hooks'
|
||||
import { useParams } from 'common'
|
||||
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal'
|
||||
import { FormSection, FormSectionContent, FormSectionLabel } from 'components/ui/Forms'
|
||||
import { useDatabaseTriggerCreateMutation } from 'data/database-triggers/database-trigger-create-mutation'
|
||||
import { useDatabaseTriggerUpdateMutation } from 'data/database-triggers/database-trigger-update-transaction-mutation'
|
||||
@@ -14,11 +14,11 @@ import {
|
||||
} from 'data/edge-functions/edge-functions-query'
|
||||
import { getTable } from 'data/tables/table-query'
|
||||
import { useTablesQuery } from 'data/tables/tables-query'
|
||||
import { useStore } from 'hooks'
|
||||
import { isValidHttpUrl, tryParseJson, uuidv4 } from 'lib/helpers'
|
||||
import { Button, Checkbox, Form, Input, Listbox, Modal, Radio, SidePanel } from 'ui'
|
||||
import { AVAILABLE_WEBHOOK_TYPES, HOOK_EVENTS } from './Hooks.constants'
|
||||
import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal'
|
||||
import HTTPRequestFields from './HTTPRequestFields'
|
||||
import { AVAILABLE_WEBHOOK_TYPES, HOOK_EVENTS } from './Hooks.constants'
|
||||
|
||||
export interface EditHookPanelProps {
|
||||
visible: boolean
|
||||
@@ -30,7 +30,6 @@ export type HTTPArgument = { id: string; name: string; value: string }
|
||||
|
||||
const EditHookPanel = ({ visible, selectedHook, onClose }: EditHookPanelProps) => {
|
||||
const { ref } = useParams()
|
||||
const { ui } = useStore()
|
||||
const submitRef = useRef<any>(null)
|
||||
const [isEdited, setIsEdited] = useState(false)
|
||||
const [isClosingPanel, setIsClosingPanel] = useState(false)
|
||||
@@ -53,38 +52,24 @@ const EditHookPanel = ({ visible, selectedHook, onClose }: EditHookPanelProps) =
|
||||
const [isSubmitting, setIsSubmitting] = useState(false)
|
||||
const { mutate: createDatabaseTrigger } = useDatabaseTriggerCreateMutation({
|
||||
onSuccess: (res) => {
|
||||
ui.setNotification({
|
||||
category: 'success',
|
||||
message: `Successfully created new webhook "${res.name}"`,
|
||||
})
|
||||
toast.success(`Successfully created new webhook "${res.name}"`)
|
||||
setIsSubmitting(false)
|
||||
onClose()
|
||||
},
|
||||
onError: (error) => {
|
||||
setIsSubmitting(false)
|
||||
ui.setNotification({
|
||||
error,
|
||||
category: 'error',
|
||||
message: `Failed to create webhook: ${error.message}`,
|
||||
})
|
||||
toast.error(`Failed to create webhook: ${error.message}`)
|
||||
},
|
||||
})
|
||||
const { mutate: updateDatabaseTrigger } = useDatabaseTriggerUpdateMutation({
|
||||
onSuccess: (res) => {
|
||||
setIsSubmitting(false)
|
||||
ui.setNotification({
|
||||
category: 'success',
|
||||
message: `Successfully updated webhook "${res.name}"`,
|
||||
})
|
||||
toast.success(`Successfully updated webhook "${res.name}"`)
|
||||
onClose()
|
||||
},
|
||||
onError: (error) => {
|
||||
setIsSubmitting(false)
|
||||
ui.setNotification({
|
||||
error,
|
||||
category: 'error',
|
||||
message: `Failed to update webhook: ${error.message}`,
|
||||
})
|
||||
toast.error(`Failed to update webhook: ${error.message}`)
|
||||
},
|
||||
})
|
||||
|
||||
@@ -204,7 +189,7 @@ const EditHookPanel = ({ visible, selectedHook, onClose }: EditHookPanelProps) =
|
||||
})
|
||||
if (!selectedTable) {
|
||||
setIsSubmitting(false)
|
||||
return ui.setNotification({ category: 'error', message: 'Unable to find selected table' })
|
||||
return toast.error('Unable to find selected table')
|
||||
}
|
||||
|
||||
const headers = httpHeaders
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
import Link from 'next/link'
|
||||
import { useEffect, useMemo, useState } from 'react'
|
||||
import { Button, Input, Listbox, SidePanel } from 'ui'
|
||||
import toast from 'react-hot-toast'
|
||||
|
||||
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import { CodeEditor } from 'components/ui/CodeEditor'
|
||||
import MultiSelect, { MultiSelectOption } from 'ui-patterns/MultiSelect'
|
||||
import ShimmeringLoader from 'components/ui/ShimmeringLoader'
|
||||
import { useIndexesQuery } from 'data/database/indexes-query'
|
||||
import { useSchemasQuery } from 'data/database/schemas-query'
|
||||
import { useTableColumnsQuery } from 'data/database/table-columns-query'
|
||||
import { useEntityTypesQuery } from 'data/entity-types/entity-types-infinite-query'
|
||||
import { useExecuteSqlMutation } from 'data/sql/execute-sql-mutation'
|
||||
import { useStore } from 'hooks'
|
||||
import { Button, Input, Listbox, SidePanel } from 'ui'
|
||||
import MultiSelect, { MultiSelectOption } from 'ui-patterns/MultiSelect'
|
||||
import { INDEX_TYPES } from './Indexes.constants'
|
||||
|
||||
interface CreateIndexSidePanelProps {
|
||||
@@ -20,7 +20,6 @@ interface CreateIndexSidePanelProps {
|
||||
}
|
||||
|
||||
const CreateIndexSidePanel = ({ visible, onClose }: CreateIndexSidePanelProps) => {
|
||||
const { ui } = useStore()
|
||||
const { project } = useProjectContext()
|
||||
const [selectedSchema, setSelectedSchema] = useState('public')
|
||||
const [selectedEntity, setSelectedEntity] = useState('---')
|
||||
@@ -58,14 +57,10 @@ const CreateIndexSidePanel = ({ visible, onClose }: CreateIndexSidePanelProps) =
|
||||
onSuccess: async () => {
|
||||
await refetchIndexes()
|
||||
onClose()
|
||||
ui.setNotification({ category: 'success', message: `Successfully created index` })
|
||||
toast.success(`Successfully created index`)
|
||||
},
|
||||
onError: (error) => {
|
||||
ui.setNotification({
|
||||
error,
|
||||
category: 'error',
|
||||
message: `Failed to create index: ${error.message}`,
|
||||
})
|
||||
toast.error(`Failed to create index: ${error.message}`)
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
import { PermissionAction } from '@supabase/shared-types/out/constants'
|
||||
import { noop } from 'lodash'
|
||||
import { useState } from 'react'
|
||||
import { Button, IconLoader } from 'ui'
|
||||
import toast from 'react-hot-toast'
|
||||
|
||||
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import AutoTextArea from 'components/to-be-cleaned/forms/AutoTextArea'
|
||||
import { executeSql } from 'data/sql/execute-sql-query'
|
||||
import { useCheckPermissions, useStore } from 'hooks'
|
||||
import { useCheckPermissions } from 'hooks'
|
||||
import { timeout } from 'lib/helpers'
|
||||
import { Button, IconLoader } from 'ui'
|
||||
|
||||
// Removes some auto-generated Postgrest text
|
||||
// Ideally PostgREST wouldn't add this if there is already a comment
|
||||
@@ -30,8 +31,6 @@ interface DescrptionProps {
|
||||
}
|
||||
|
||||
const Description = ({ content, metadata, onChange = noop }: DescrptionProps) => {
|
||||
const { ui } = useStore()
|
||||
|
||||
const contentText = temp_removePostgrestText(content || '').trim()
|
||||
const [value, setValue] = useState(contentText)
|
||||
const [isUpdating, setIsUpdating] = useState(false)
|
||||
@@ -62,20 +61,11 @@ const Description = ({ content, metadata, onChange = noop }: DescrptionProps) =>
|
||||
connectionString: project?.connectionString,
|
||||
sql: query,
|
||||
})
|
||||
|
||||
// [Joshen] Temp fix, immediately refreshing the docs fetches stale state
|
||||
await timeout(500)
|
||||
|
||||
ui.setNotification({
|
||||
category: 'success',
|
||||
message: `Successfully updated description`,
|
||||
})
|
||||
toast.success(`Successfully updated description`)
|
||||
} catch (error: any) {
|
||||
ui.setNotification({
|
||||
error: error,
|
||||
category: 'error',
|
||||
message: `Failed to update description: ${error.message}`,
|
||||
})
|
||||
toast.error(`Failed to update description: ${error.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import Link from 'next/link'
|
||||
import { useState } from 'react'
|
||||
import { Button, IconDownload, IconExternalLink } from 'ui'
|
||||
import toast from 'react-hot-toast'
|
||||
|
||||
import { useParams } from 'common/hooks'
|
||||
import { useParams } from 'common'
|
||||
import CodeSnippet from 'components/interfaces/Docs/CodeSnippet'
|
||||
import { generateTypes } from 'data/projects/project-type-generation-query'
|
||||
import { useStore } from 'hooks'
|
||||
import { Button, IconDownload, IconExternalLink } from 'ui'
|
||||
|
||||
interface Props {
|
||||
selectedLang: 'bash' | 'js'
|
||||
@@ -13,7 +13,6 @@ interface Props {
|
||||
|
||||
export default function GeneratingTypes({ selectedLang }: Props) {
|
||||
const { ref } = useParams()
|
||||
const { ui } = useStore()
|
||||
const [isGeneratingTypes, setIsGeneratingTypes] = useState(false)
|
||||
|
||||
const onClickGenerateTypes = async () => {
|
||||
@@ -27,16 +26,9 @@ export default function GeneratingTypes({ selectedLang }: Props) {
|
||||
document.body.appendChild(element)
|
||||
element.click()
|
||||
document.body.removeChild(element)
|
||||
ui.setNotification({
|
||||
category: 'success',
|
||||
message: `Successfully generated types! File is being downloaded`,
|
||||
})
|
||||
toast.success(`Successfully generated types! File is being downloaded`)
|
||||
} catch (error: any) {
|
||||
ui.setNotification({
|
||||
error,
|
||||
category: 'error',
|
||||
message: `Failed to generate types: ${error.message}`,
|
||||
})
|
||||
toast.error(`Failed to generate types: ${error.message}`)
|
||||
} finally {
|
||||
setIsGeneratingTypes(false)
|
||||
}
|
||||
|
||||
+16
-19
@@ -6,18 +6,7 @@ import dayjs from 'dayjs'
|
||||
import Link from 'next/link'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useEffect, useMemo, useState } from 'react'
|
||||
import {
|
||||
Alert,
|
||||
Button,
|
||||
Form,
|
||||
IconExternalLink,
|
||||
IconMaximize2,
|
||||
IconMinimize2,
|
||||
IconTerminal,
|
||||
Input,
|
||||
Modal,
|
||||
Toggle,
|
||||
} from 'ui'
|
||||
import toast from 'react-hot-toast'
|
||||
|
||||
import {
|
||||
FormActions,
|
||||
@@ -33,13 +22,24 @@ import { useCustomDomainsQuery } from 'data/custom-domains/custom-domains-query'
|
||||
import { useEdgeFunctionQuery } from 'data/edge-functions/edge-function-query'
|
||||
import { useEdgeFunctionDeleteMutation } from 'data/edge-functions/edge-functions-delete-mutation'
|
||||
import { useEdgeFunctionUpdateMutation } from 'data/edge-functions/edge-functions-update-mutation'
|
||||
import { useCheckPermissions, useStore } from 'hooks'
|
||||
import { useCheckPermissions } from 'hooks'
|
||||
import {
|
||||
Alert,
|
||||
Button,
|
||||
Form,
|
||||
IconExternalLink,
|
||||
IconMaximize2,
|
||||
IconMinimize2,
|
||||
IconTerminal,
|
||||
Input,
|
||||
Modal,
|
||||
Toggle,
|
||||
} from 'ui'
|
||||
import CommandRender from '../CommandRender'
|
||||
import { generateCLICommands } from './EdgeFunctionDetails.utils'
|
||||
|
||||
const EdgeFunctionDetails = () => {
|
||||
const router = useRouter()
|
||||
const { ui } = useStore()
|
||||
const { ref: projectRef, functionSlug } = useParams()
|
||||
const [showDeleteModal, setShowDeleteModal] = useState(false)
|
||||
const [showInstructions, setShowInstructions] = useState(false)
|
||||
@@ -50,10 +50,7 @@ const EdgeFunctionDetails = () => {
|
||||
const { mutateAsync: updateEdgeFunction, isLoading: isUpdating } = useEdgeFunctionUpdateMutation()
|
||||
const { mutate: deleteEdgeFunction, isLoading: isDeleting } = useEdgeFunctionDeleteMutation({
|
||||
onSuccess: () => {
|
||||
ui.setNotification({
|
||||
category: 'success',
|
||||
message: `Successfully deleted "${selectedFunction?.name}"`,
|
||||
})
|
||||
toast.success(`Successfully deleted "${selectedFunction?.name}"`)
|
||||
router.push(`/project/${projectRef}/functions`)
|
||||
},
|
||||
})
|
||||
@@ -90,7 +87,7 @@ const EdgeFunctionDetails = () => {
|
||||
payload: values,
|
||||
})
|
||||
resetForm({ values, initialValues: values })
|
||||
ui.setNotification({ category: 'success', message: `Successfully updated edge function` })
|
||||
toast.success(`Successfully updated edge function`)
|
||||
} catch (error) {}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { PermissionAction } from '@supabase/shared-types/out/constants'
|
||||
import { useQueryClient } from '@tanstack/react-query'
|
||||
import { useEffect } from 'react'
|
||||
import toast from 'react-hot-toast'
|
||||
|
||||
import { useParams } from 'common'
|
||||
import {
|
||||
@@ -11,11 +12,10 @@ import {
|
||||
import { FormActions, FormPanel, FormSection, FormSectionContent } from 'components/ui/Forms'
|
||||
import { useOrganizationUpdateMutation } from 'data/organizations/organization-update-mutation'
|
||||
import { invalidateOrganizationsQuery } from 'data/organizations/organizations-query'
|
||||
import { useCheckPermissions, useSelectedOrganization, useStore } from 'hooks'
|
||||
import { useCheckPermissions, useSelectedOrganization } from 'hooks'
|
||||
import { Form, Input } from 'ui'
|
||||
|
||||
const BillingEmail = () => {
|
||||
const { ui } = useStore()
|
||||
const { slug } = useParams()
|
||||
const queryClient = useQueryClient()
|
||||
const selectedOrganization = useSelectedOrganization()
|
||||
@@ -30,10 +30,7 @@ const BillingEmail = () => {
|
||||
|
||||
const onUpdateOrganizationEmail = async (values: any, { resetForm }: any) => {
|
||||
if (!canUpdateOrganization) {
|
||||
return ui.setNotification({
|
||||
category: 'error',
|
||||
message: 'You do not have the required permissions to update this organization',
|
||||
})
|
||||
return toast.error('You do not have the required permissions to update this organization')
|
||||
}
|
||||
if (!slug) return console.error('Slug is required')
|
||||
if (!name) return console.error('Organization name is required')
|
||||
@@ -46,10 +43,7 @@ const BillingEmail = () => {
|
||||
})
|
||||
resetForm({ values: { billing_email }, initialValues: { billing_email } })
|
||||
invalidateOrganizationsQuery(queryClient)
|
||||
ui.setNotification({
|
||||
category: 'success',
|
||||
message: 'Successfully saved settings',
|
||||
})
|
||||
toast.success('Successfully saved settings')
|
||||
} finally {
|
||||
}
|
||||
}
|
||||
|
||||
+16
-24
@@ -1,20 +1,21 @@
|
||||
import { PermissionAction } from '@supabase/shared-types/out/constants'
|
||||
import clsx from 'clsx'
|
||||
import { useParams } from 'common'
|
||||
import { useTheme } from 'next-themes'
|
||||
import Table from 'components/to-be-cleaned/Table'
|
||||
import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query'
|
||||
import { useOrgSubscriptionUpdateMutation } from 'data/subscriptions/org-subscription-update-mutation'
|
||||
import { useCheckPermissions, useStore } from 'hooks'
|
||||
import { BASE_PATH, PRICING_TIER_PRODUCT_IDS } from 'lib/constants'
|
||||
import Telemetry from 'lib/telemetry'
|
||||
import Image from 'next/image'
|
||||
import Link from 'next/link'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useEffect, useState } from 'react'
|
||||
import toast from 'react-hot-toast'
|
||||
|
||||
import { useParams } from 'common'
|
||||
import Table from 'components/to-be-cleaned/Table'
|
||||
import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query'
|
||||
import { useOrgSubscriptionUpdateMutation } from 'data/subscriptions/org-subscription-update-mutation'
|
||||
import { useCheckPermissions } from 'hooks'
|
||||
import { BASE_PATH, PRICING_TIER_PRODUCT_IDS } from 'lib/constants'
|
||||
import Telemetry from 'lib/telemetry'
|
||||
import { pricing } from 'shared-data/pricing'
|
||||
import { useOrgSettingsPageStateSnapshot } from 'state/organization-settings'
|
||||
import { Alert, Button, Collapsible, IconChevronRight, IconExternalLink, SidePanel } from 'ui'
|
||||
import Image from 'next/image'
|
||||
import { Alert, Button, Collapsible, IconChevronRight, IconExternalLink, SidePanel, cn } from 'ui'
|
||||
|
||||
const SPEND_CAP_OPTIONS: {
|
||||
name: string
|
||||
@@ -37,7 +38,6 @@ const SPEND_CAP_OPTIONS: {
|
||||
]
|
||||
|
||||
const SpendCapSidePanel = () => {
|
||||
const { ui } = useStore()
|
||||
const router = useRouter()
|
||||
const { slug } = useParams()
|
||||
const { resolvedTheme } = useTheme()
|
||||
@@ -58,19 +58,11 @@ const SpendCapSidePanel = () => {
|
||||
const { mutate: updateOrgSubscription, isLoading: isUpdating } = useOrgSubscriptionUpdateMutation(
|
||||
{
|
||||
onSuccess: () => {
|
||||
ui.setNotification({
|
||||
category: 'success',
|
||||
message: `Successfully ${isTurningOnCap ? 'enabled' : 'disabled'} spend cap`,
|
||||
})
|
||||
|
||||
toast.success(`Successfully ${isTurningOnCap ? 'enabled' : 'disabled'} spend cap`)
|
||||
onClose()
|
||||
},
|
||||
onError: (error) => {
|
||||
ui.setNotification({
|
||||
error,
|
||||
category: 'error',
|
||||
message: `Failed to toggle spend cap: ${error.message}`,
|
||||
})
|
||||
toast.error(`Failed to toggle spend cap: ${error.message}`)
|
||||
},
|
||||
}
|
||||
)
|
||||
@@ -228,7 +220,7 @@ const SpendCapSidePanel = () => {
|
||||
return (
|
||||
<div
|
||||
key={option.value}
|
||||
className={clsx('col-span-4 group space-y-1', isFreePlan && 'opacity-75')}
|
||||
className={cn('col-span-4 group space-y-1', isFreePlan && 'opacity-75')}
|
||||
onClick={() => {
|
||||
!isFreePlan && setSelectedOption(option.value)
|
||||
Telemetry.sendActivity(
|
||||
@@ -248,7 +240,7 @@ const SpendCapSidePanel = () => {
|
||||
>
|
||||
<Image
|
||||
alt="Spend Cap"
|
||||
className={clsx(
|
||||
className={cn(
|
||||
'relative rounded-xl transition border bg-no-repeat bg-center bg-cover w-[160px] h-[96px]',
|
||||
isSelected
|
||||
? 'border-foreground'
|
||||
@@ -262,7 +254,7 @@ const SpendCapSidePanel = () => {
|
||||
/>
|
||||
|
||||
<p
|
||||
className={clsx(
|
||||
className={cn(
|
||||
'text-sm transition',
|
||||
!isFreePlan && 'group-hover:text-foreground',
|
||||
isSelected ? 'text-foreground' : 'text-foreground-light'
|
||||
|
||||
+7
-11
@@ -1,9 +1,10 @@
|
||||
import toast from 'react-hot-toast'
|
||||
|
||||
import { useParams } from 'common'
|
||||
import type { OrganizationPaymentMethod } from 'data/organizations/organization-payment-methods-query'
|
||||
import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query'
|
||||
import { useOrgSubscriptionUpdateMutation } from 'data/subscriptions/org-subscription-update-mutation'
|
||||
import type { SubscriptionTier } from 'data/subscriptions/types'
|
||||
import { useStore } from 'hooks'
|
||||
import { Button, Modal } from 'ui'
|
||||
|
||||
export interface ChangePaymentMethodModalProps {
|
||||
@@ -15,25 +16,20 @@ const ChangePaymentMethodModal = ({
|
||||
selectedPaymentMethod,
|
||||
onClose,
|
||||
}: ChangePaymentMethodModalProps) => {
|
||||
const { ui } = useStore()
|
||||
const { slug } = useParams()
|
||||
const { data: subscription } = useOrgSubscriptionQuery({ orgSlug: slug })
|
||||
const { mutate: updateOrgSubscription, isLoading: isUpdating } = useOrgSubscriptionUpdateMutation(
|
||||
{
|
||||
onSuccess: () => {
|
||||
ui.setNotification({
|
||||
category: 'success',
|
||||
message: `Successfully changed payment method to the card ending with ${
|
||||
toast.success(
|
||||
`Successfully changed payment method to the card ending with ${
|
||||
selectedPaymentMethod!.card.last4
|
||||
}`,
|
||||
})
|
||||
}`
|
||||
)
|
||||
onClose()
|
||||
},
|
||||
onError: (error) => {
|
||||
ui.setNotification({
|
||||
category: 'error',
|
||||
message: `Failed to change payment method: ${error.message}`,
|
||||
})
|
||||
toast.error(`Failed to change payment method: ${error.message}`)
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
+11
-17
@@ -1,15 +1,16 @@
|
||||
import HCaptcha from '@hcaptcha/react-hcaptcha'
|
||||
import { includes, without } from 'lodash'
|
||||
import { useReducer, useRef, useState } from 'react'
|
||||
import toast from 'react-hot-toast'
|
||||
|
||||
import { useParams } from 'common'
|
||||
import { useSendDowngradeFeedbackMutation } from 'data/feedback/exit-survey-send'
|
||||
import type { OrgSubscription } from 'data/subscriptions/types'
|
||||
import { useOrgSubscriptionUpdateMutation } from 'data/subscriptions/org-subscription-update-mutation'
|
||||
import { useFlag, useStore } from 'hooks'
|
||||
import type { OrgSubscription } from 'data/subscriptions/types'
|
||||
import { useFlag } from 'hooks'
|
||||
import { Alert, Button, Input, Modal } from 'ui'
|
||||
import ProjectUpdateDisabledTooltip from '../ProjectUpdateDisabledTooltip'
|
||||
import { CANCELLATION_REASONS } from '../BillingSettings.constants'
|
||||
import ProjectUpdateDisabledTooltip from '../ProjectUpdateDisabledTooltip'
|
||||
|
||||
export interface ExitSurveyModalProps {
|
||||
visible: boolean
|
||||
@@ -19,7 +20,6 @@ export interface ExitSurveyModalProps {
|
||||
|
||||
// [Joshen] For context - Exit survey is only when going to free plan from a paid plan
|
||||
const ExitSurveyModal = ({ visible, subscription, onClose }: ExitSurveyModalProps) => {
|
||||
const { ui } = useStore()
|
||||
const { slug } = useParams()
|
||||
const captchaRef = useRef<HCaptcha>(null)
|
||||
|
||||
@@ -33,10 +33,7 @@ const ExitSurveyModal = ({ visible, subscription, onClose }: ExitSurveyModalProp
|
||||
const { mutateAsync: updateOrgSubscription, isLoading: isUpdating } =
|
||||
useOrgSubscriptionUpdateMutation({
|
||||
onError: (error) => {
|
||||
ui.setNotification({
|
||||
category: 'error',
|
||||
message: `Failed to downgrade project: ${error.message}`,
|
||||
})
|
||||
toast.error(`Failed to downgrade project: ${error.message}`)
|
||||
},
|
||||
})
|
||||
const isSubmitting = isUpdating || isSubmittingFeedback
|
||||
@@ -62,10 +59,7 @@ const ExitSurveyModal = ({ visible, subscription, onClose }: ExitSurveyModalProp
|
||||
|
||||
const onSubmit = async () => {
|
||||
if (selectedReasons.length === 0) {
|
||||
return ui.setNotification({
|
||||
category: 'error',
|
||||
message: 'Please select at least one reason for canceling your subscription',
|
||||
})
|
||||
return toast.error('Please select at least one reason for canceling your subscription')
|
||||
}
|
||||
|
||||
let token = captchaToken
|
||||
@@ -98,13 +92,13 @@ const ExitSurveyModal = ({ visible, subscription, onClose }: ExitSurveyModalProp
|
||||
} finally {
|
||||
}
|
||||
|
||||
ui.setNotification({
|
||||
category: 'success',
|
||||
duration: hasComputeInstance ? 8000 : 4000,
|
||||
message: hasComputeInstance
|
||||
toast.success(
|
||||
hasComputeInstance
|
||||
? 'Your organization has been downgraded and your projects are currently restarting to update their compute instances'
|
||||
: 'Successfully downgraded organization to the free plan',
|
||||
})
|
||||
{ duration: hasComputeInstance ? 8000 : 4000 }
|
||||
)
|
||||
|
||||
onClose(true)
|
||||
window.scrollTo({ top: 0, left: 0, behavior: 'smooth' })
|
||||
}
|
||||
|
||||
+11
-18
@@ -1,10 +1,10 @@
|
||||
import * as Tooltip from '@radix-ui/react-tooltip'
|
||||
import { PermissionAction } from '@supabase/shared-types/out/constants'
|
||||
import clsx from 'clsx'
|
||||
import { isArray } from 'lodash'
|
||||
import Link from 'next/link'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { plans as subscriptionsPlans } from 'shared-data/plans'
|
||||
import toast from 'react-hot-toast'
|
||||
|
||||
import Table from 'components/to-be-cleaned/Table'
|
||||
import AlertError from 'components/ui/AlertError'
|
||||
@@ -12,13 +12,16 @@ import InformationBox from 'components/ui/InformationBox'
|
||||
import ShimmeringLoader from 'components/ui/ShimmeringLoader'
|
||||
import { useFreeProjectLimitCheckQuery } from 'data/organizations/free-project-limit-check-query'
|
||||
import { useOrganizationBillingSubscriptionPreview } from 'data/organizations/organization-billing-subscription-preview'
|
||||
import { useProjectsQuery } from 'data/projects/projects-query'
|
||||
import { useOrgPlansQuery } from 'data/subscriptions/org-plans-query'
|
||||
import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query'
|
||||
import { useOrgSubscriptionUpdateMutation } from 'data/subscriptions/org-subscription-update-mutation'
|
||||
import type { OrgPlan, SubscriptionTier } from 'data/subscriptions/types'
|
||||
import { useCheckPermissions, useSelectedOrganization, useStore } from 'hooks'
|
||||
import { PRICING_TIER_PRODUCT_IDS } from 'lib/constants'
|
||||
import { formatCurrency } from 'lib/helpers'
|
||||
import Telemetry from 'lib/telemetry'
|
||||
import { plans as subscriptionsPlans } from 'shared-data/plans'
|
||||
import { useOrgSettingsPageStateSnapshot } from 'state/organization-settings'
|
||||
import {
|
||||
Button,
|
||||
@@ -28,18 +31,15 @@ import {
|
||||
IconInfo,
|
||||
Modal,
|
||||
SidePanel,
|
||||
cn,
|
||||
} from 'ui'
|
||||
import DowngradeModal from './DowngradeModal'
|
||||
import EnterpriseCard from './EnterpriseCard'
|
||||
import ExitSurveyModal from './ExitSurveyModal'
|
||||
import MembersExceedLimitModal from './MembersExceedLimitModal'
|
||||
import PaymentMethodSelection from './PaymentMethodSelection'
|
||||
import { formatCurrency } from 'lib/helpers'
|
||||
import { useProjectsQuery } from 'data/projects/projects-query'
|
||||
import { isArray } from 'lodash'
|
||||
|
||||
const PlanUpdateSidePanel = () => {
|
||||
const { ui } = useStore()
|
||||
const router = useRouter()
|
||||
const selectedOrganization = useSelectedOrganization()
|
||||
const slug = selectedOrganization?.slug
|
||||
@@ -75,20 +75,13 @@ const PlanUpdateSidePanel = () => {
|
||||
const { mutate: updateOrgSubscription, isLoading: isUpdating } = useOrgSubscriptionUpdateMutation(
|
||||
{
|
||||
onSuccess: () => {
|
||||
ui.setNotification({
|
||||
category: 'success',
|
||||
message: `Successfully updated subscription to ${subscriptionPlanMeta?.name}!`,
|
||||
})
|
||||
toast.success(`Successfully updated subscription to ${subscriptionPlanMeta?.name}!`)
|
||||
setSelectedTier(undefined)
|
||||
onClose()
|
||||
window.scrollTo({ top: 0, left: 0, behavior: 'smooth' })
|
||||
},
|
||||
onError: (error) => {
|
||||
ui.setNotification({
|
||||
error,
|
||||
category: 'error',
|
||||
message: `Unable to update subscription: ${error.message}`,
|
||||
})
|
||||
toast.error(`Unable to update subscription: ${error.message}`)
|
||||
},
|
||||
}
|
||||
)
|
||||
@@ -147,7 +140,7 @@ const PlanUpdateSidePanel = () => {
|
||||
if (!slug) return console.error('org slug is required')
|
||||
if (!selectedTier) return console.error('Selected plan is required')
|
||||
if (!selectedPaymentMethod && !paymentViaInvoice) {
|
||||
return ui.setNotification({ category: 'error', message: 'Please select a payment method' })
|
||||
return toast.error('Please select a payment method')
|
||||
}
|
||||
|
||||
// If the user is downgrading from team, should have spend cap disabled by default
|
||||
@@ -210,7 +203,7 @@ const PlanUpdateSidePanel = () => {
|
||||
>
|
||||
<div className="w-full">
|
||||
<div className="flex items-center space-x-2">
|
||||
<p className={clsx('text-brand text-sm uppercase')}>{plan.name}</p>
|
||||
<p className={cn('text-brand text-sm uppercase')}>{plan.name}</p>
|
||||
{isCurrentPlan ? (
|
||||
<div className="text-xs bg-surface-300 text-foreground-light rounded px-2 py-0.5">
|
||||
Current plan
|
||||
@@ -394,7 +387,7 @@ const PlanUpdateSidePanel = () => {
|
||||
className="!pl-0 !pr-1"
|
||||
icon={
|
||||
<IconChevronRight
|
||||
className={clsx(
|
||||
className={cn(
|
||||
'transition',
|
||||
usageFeesExpanded.includes(item.description) && 'rotate-90'
|
||||
)}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { PermissionAction } from '@supabase/shared-types/out/constants'
|
||||
import { useEffect, useState } from 'react'
|
||||
import toast from 'react-hot-toast'
|
||||
|
||||
import { useParams } from 'common'
|
||||
import {
|
||||
@@ -16,14 +17,13 @@ import {
|
||||
TaxIdValue,
|
||||
useOrganizationTaxIDsUpdateMutation,
|
||||
} from 'data/organizations/organization-tax-ids-update-mutation'
|
||||
import { useCheckPermissions, useStore } from 'hooks'
|
||||
import { useCheckPermissions } from 'hooks'
|
||||
import { uuidv4 } from 'lib/helpers'
|
||||
import { Button, Form, IconPlus, IconX, Input, Listbox } from 'ui'
|
||||
import { TAX_IDS } from './TaxID.constants'
|
||||
import { checkTaxIdsEqual, sanitizeTaxID } from './TaxID.utilts'
|
||||
|
||||
const TaxID = () => {
|
||||
const { ui } = useStore()
|
||||
const { slug } = useParams()
|
||||
const {
|
||||
data: taxIds,
|
||||
@@ -52,10 +52,10 @@ const TaxID = () => {
|
||||
|
||||
if (errors !== undefined && errors.length > 0) {
|
||||
errors.forEach((taxId: any) => {
|
||||
ui.setNotification({ category: 'error', message: taxId.result.error.message })
|
||||
toast.error(taxId.result.error.message)
|
||||
})
|
||||
} else {
|
||||
ui.setNotification({ category: 'success', message: 'Successfully updated tax IDs' })
|
||||
toast.success('Successfully updated tax IDs')
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
+5
-12
@@ -1,15 +1,14 @@
|
||||
import { PermissionAction } from '@supabase/shared-types/out/constants'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useState } from 'react'
|
||||
import { Button, Form, Input, Modal } from 'ui'
|
||||
import toast from 'react-hot-toast'
|
||||
|
||||
import { useOrganizationDeleteMutation } from 'data/organizations/organization-delete-mutation'
|
||||
import { useCheckPermissions, useSelectedOrganization, useStore } from 'hooks'
|
||||
import { useCheckPermissions, useSelectedOrganization } from 'hooks'
|
||||
import { Button, Form, Input, Modal } from 'ui'
|
||||
|
||||
const DeleteOrganizationButton = () => {
|
||||
const router = useRouter()
|
||||
const { ui } = useStore()
|
||||
|
||||
const selectedOrganization = useSelectedOrganization()
|
||||
const { slug: orgSlug, name: orgName } = selectedOrganization ?? {}
|
||||
|
||||
@@ -32,20 +31,14 @@ const DeleteOrganizationButton = () => {
|
||||
|
||||
const onConfirmDelete = async (values: any) => {
|
||||
if (!canDeleteOrganization) {
|
||||
return ui.setNotification({
|
||||
category: 'error',
|
||||
message: 'You do not have the required permissions to delete this organization',
|
||||
})
|
||||
return toast.error('You do not have the required permissions to delete this organization')
|
||||
}
|
||||
if (!orgSlug) return console.error('Org slug is required')
|
||||
|
||||
try {
|
||||
await deleteOrganization({ slug: orgSlug })
|
||||
} finally {
|
||||
ui.setNotification({
|
||||
category: 'success',
|
||||
message: `Successfully deleted ${orgName}`,
|
||||
})
|
||||
toast.success(`Successfully deleted ${orgName}`)
|
||||
router.push('/projects')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import { PermissionAction } from '@supabase/shared-types/out/constants'
|
||||
import { useQueryClient } from '@tanstack/react-query'
|
||||
import clsx from 'clsx'
|
||||
import { useParams } from 'common'
|
||||
import { observer } from 'mobx-react-lite'
|
||||
import Link from 'next/link'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { Collapsible, Form, IconChevronRight, Input, Toggle } from 'ui'
|
||||
import toast from 'react-hot-toast'
|
||||
|
||||
import NoProjectsOnPaidOrgInfo from 'components/interfaces/Billing/NoProjectsOnPaidOrgInfo'
|
||||
import { ScaffoldContainerLegacy } from 'components/layouts/Scaffold'
|
||||
@@ -18,13 +17,13 @@ import {
|
||||
} from 'components/ui/Forms'
|
||||
import { useOrganizationUpdateMutation } from 'data/organizations/organization-update-mutation'
|
||||
import { invalidateOrganizationsQuery } from 'data/organizations/organizations-query'
|
||||
import { useCheckPermissions, useIsFeatureEnabled, useSelectedOrganization, useStore } from 'hooks'
|
||||
import { useCheckPermissions, useIsFeatureEnabled, useSelectedOrganization } from 'hooks'
|
||||
import { OPT_IN_TAGS } from 'lib/constants'
|
||||
import { Collapsible, Form, IconChevronRight, Input, Toggle, cn } from 'ui'
|
||||
import OrganizationDeletePanel from './OrganizationDeletePanel'
|
||||
|
||||
const GeneralSettings = () => {
|
||||
const queryClient = useQueryClient()
|
||||
const { ui } = useStore()
|
||||
const { slug } = useParams()
|
||||
const [open, setOpen] = useState(false)
|
||||
const selectedOrganization = useSelectedOrganization()
|
||||
@@ -42,10 +41,7 @@ const GeneralSettings = () => {
|
||||
|
||||
const onUpdateOrganization = async (values: any, { resetForm }: any) => {
|
||||
if (!canUpdateOrganization) {
|
||||
return ui.setNotification({
|
||||
category: 'error',
|
||||
message: 'You do not have the required permissions to update this organization',
|
||||
})
|
||||
return toast.error('You do not have the required permissions to update this organization')
|
||||
}
|
||||
|
||||
if (!slug) return console.error('Slug is required')
|
||||
@@ -64,7 +60,7 @@ const GeneralSettings = () => {
|
||||
onSuccess: () => {
|
||||
resetForm({ values, initialValues: values })
|
||||
invalidateOrganizationsQuery(queryClient)
|
||||
ui.setNotification({ category: 'success', message: 'Successfully saved settings' })
|
||||
toast.success('Successfully saved settings')
|
||||
},
|
||||
}
|
||||
)
|
||||
@@ -135,7 +131,7 @@ const GeneralSettings = () => {
|
||||
<IconChevronRight
|
||||
strokeWidth={2}
|
||||
size={16}
|
||||
className={clsx('transition-all', open ? 'rotate-90' : '')}
|
||||
className={cn('transition-all', open ? 'rotate-90' : '')}
|
||||
/>
|
||||
<p className="text-sm text-foreground-light underline">
|
||||
Important information regarding opting in
|
||||
|
||||
@@ -1,29 +1,18 @@
|
||||
import { PaymentElement, useElements, useStripe } from '@stripe/react-stripe-js'
|
||||
import type { PaymentMethod } from '@stripe/stripe-js'
|
||||
import { useQueryClient } from '@tanstack/react-query'
|
||||
import Link from 'next/link'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useEffect, useState } from 'react'
|
||||
import {
|
||||
Button,
|
||||
IconEdit2,
|
||||
IconExternalLink,
|
||||
IconHelpCircle,
|
||||
IconInfo,
|
||||
Input,
|
||||
Listbox,
|
||||
Toggle,
|
||||
} from 'ui'
|
||||
import toast from 'react-hot-toast'
|
||||
|
||||
import { useParams } from 'common'
|
||||
import SpendCapModal from 'components/interfaces/Billing/SpendCapModal'
|
||||
import InformationBox from 'components/ui/InformationBox'
|
||||
import Panel from 'components/ui/Panel'
|
||||
import { useOrganizationCreateMutation } from 'data/organizations/organization-create-mutation'
|
||||
import { invalidateOrganizationsQuery } from 'data/organizations/organizations-query'
|
||||
import { useStore } from 'hooks'
|
||||
import { BASE_PATH, PRICING_TIER_LABELS_ORG } from 'lib/constants'
|
||||
import { getURL } from 'lib/helpers'
|
||||
import { Button, IconEdit2, IconHelpCircle, Input, Listbox, Toggle } from 'ui'
|
||||
|
||||
const ORG_KIND_TYPES = {
|
||||
PERSONAL: 'Personal',
|
||||
@@ -52,12 +41,10 @@ interface NewOrgFormProps {
|
||||
* No org selected yet, create a new one
|
||||
*/
|
||||
const NewOrgForm = ({ onPaymentMethodReset }: NewOrgFormProps) => {
|
||||
const queryClient = useQueryClient()
|
||||
const { ui } = useStore()
|
||||
const router = useRouter()
|
||||
const stripe = useStripe()
|
||||
const elements = useElements()
|
||||
|
||||
const queryClient = useQueryClient()
|
||||
const { plan, name, kind, size, spend_cap } = useParams()
|
||||
|
||||
const [orgName, setOrgName] = useState(name || '')
|
||||
@@ -142,7 +129,7 @@ const NewOrgForm = ({ onPaymentMethodReset }: NewOrgFormProps) => {
|
||||
|
||||
const isOrgNameValid = validateOrgName(orgName)
|
||||
if (!isOrgNameValid) {
|
||||
return ui.setNotification({ category: 'error', message: 'Organization name is empty' })
|
||||
return toast.error('Organization name is empty')
|
||||
}
|
||||
|
||||
if (!stripe || !elements) {
|
||||
@@ -163,10 +150,7 @@ const NewOrgForm = ({ onPaymentMethodReset }: NewOrgFormProps) => {
|
||||
})
|
||||
|
||||
if (error || !setupIntent.payment_method) {
|
||||
ui.setNotification({
|
||||
category: 'error',
|
||||
message: error?.message ?? ' Failed to save card details',
|
||||
})
|
||||
toast.error(error?.message ?? ' Failed to save card details')
|
||||
setNewOrgLoading(false)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import toast from 'react-hot-toast'
|
||||
|
||||
import { useParams } from 'common'
|
||||
import { useOAuthAppDeleteMutation } from 'data/oauth/oauth-app-delete-mutation'
|
||||
import type { OAuthApp } from 'data/oauth/oauth-apps-query'
|
||||
import { useStore } from 'hooks'
|
||||
import { Alert, IconLock, Modal } from 'ui'
|
||||
|
||||
export interface DeleteAppModalProps {
|
||||
@@ -10,14 +11,10 @@ export interface DeleteAppModalProps {
|
||||
}
|
||||
|
||||
const DeleteAppModal = ({ selectedApp, onClose }: DeleteAppModalProps) => {
|
||||
const { ui } = useStore()
|
||||
const { slug } = useParams()
|
||||
const { mutate: deleteOAuthApp, isLoading: isDeleting } = useOAuthAppDeleteMutation({
|
||||
onSuccess: () => {
|
||||
ui.setNotification({
|
||||
category: 'success',
|
||||
message: `Successfully deleted the app "${selectedApp?.name}"`,
|
||||
})
|
||||
toast.success(`Successfully deleted the app "${selectedApp?.name}"`)
|
||||
onClose()
|
||||
},
|
||||
})
|
||||
|
||||
+11
-26
@@ -1,7 +1,8 @@
|
||||
import clsx from 'clsx'
|
||||
import { ChangeEvent, useEffect, useRef, useState } from 'react'
|
||||
|
||||
import type { OAuthScope } from '@supabase/shared-types/out/constants'
|
||||
import Link from 'next/link'
|
||||
import { ChangeEvent, useEffect, useRef, useState } from 'react'
|
||||
import toast from 'react-hot-toast'
|
||||
|
||||
import { useParams } from 'common'
|
||||
import {
|
||||
OAuthAppCreateResponse,
|
||||
@@ -9,7 +10,6 @@ import {
|
||||
} from 'data/oauth/oauth-app-create-mutation'
|
||||
import { useOAuthAppUpdateMutation } from 'data/oauth/oauth-app-update-mutation'
|
||||
import type { OAuthApp } from 'data/oauth/oauth-apps-query'
|
||||
import { useStore } from 'hooks'
|
||||
import { isValidHttpUrl, uuidv4 } from 'lib/helpers'
|
||||
import { uploadAttachment } from 'lib/upload'
|
||||
import {
|
||||
@@ -26,10 +26,10 @@ import {
|
||||
Input,
|
||||
Modal,
|
||||
SidePanel,
|
||||
cn,
|
||||
} from 'ui'
|
||||
import AuthorizeRequesterDetails from '../AuthorizeRequesterDetails'
|
||||
import { ScopesPanel } from './Scopes'
|
||||
import Link from 'next/link'
|
||||
|
||||
export interface PublishAppSidePanelProps {
|
||||
visible: boolean
|
||||
@@ -44,43 +44,28 @@ const PublishAppSidePanel = ({
|
||||
onClose,
|
||||
onCreateSuccess,
|
||||
}: PublishAppSidePanelProps) => {
|
||||
const { ui } = useStore()
|
||||
const { slug } = useParams()
|
||||
const uploadButtonRef = useRef<any>()
|
||||
const { mutate: createOAuthApp } = useOAuthAppCreateMutation({
|
||||
onSuccess: (res, variables) => {
|
||||
ui.setNotification({
|
||||
category: 'success',
|
||||
message: `Successfully created OAuth app "${variables.name}"!`,
|
||||
})
|
||||
toast.success(`Successfully created OAuth app "${variables.name}"!`)
|
||||
onClose()
|
||||
onCreateSuccess(res)
|
||||
setIsSubmitting(false)
|
||||
},
|
||||
onError: (error) => {
|
||||
ui.setNotification({
|
||||
error,
|
||||
category: 'error',
|
||||
message: `Failed to create OAuth application: ${error.message}`,
|
||||
})
|
||||
toast.error(`Failed to create OAuth application: ${error.message}`)
|
||||
setIsSubmitting(false)
|
||||
},
|
||||
})
|
||||
const { mutate: updateOAuthApp } = useOAuthAppUpdateMutation({
|
||||
onSuccess: (res, variables) => {
|
||||
ui.setNotification({
|
||||
category: 'success',
|
||||
message: `Successfully updated OAuth app "${variables.name}"!`,
|
||||
})
|
||||
toast.success(`Successfully updated OAuth app "${variables.name}"!`)
|
||||
onClose()
|
||||
setIsSubmitting(false)
|
||||
},
|
||||
onError: (error) => {
|
||||
ui.setNotification({
|
||||
error,
|
||||
category: 'error',
|
||||
message: `Failed to update OAuth application: ${error.message}`,
|
||||
})
|
||||
toast.error(`Failed to update OAuth application: ${error.message}`)
|
||||
setIsSubmitting(false)
|
||||
},
|
||||
})
|
||||
@@ -239,7 +224,7 @@ const PublishAppSidePanel = ({
|
||||
<div>
|
||||
{iconUrl !== undefined ? (
|
||||
<div
|
||||
className={clsx(
|
||||
className={cn(
|
||||
'shadow transition group relative',
|
||||
'bg-center bg-cover bg-no-repeat',
|
||||
'mt-4 mr-4 space-y-2 rounded-full h-[120px] w-[120px] flex flex-col items-center justify-center'
|
||||
@@ -280,7 +265,7 @@ const PublishAppSidePanel = ({
|
||||
</div>
|
||||
) : (
|
||||
<div
|
||||
className={clsx(
|
||||
className={cn(
|
||||
'border border-strong transition opacity-75 hover:opacity-100',
|
||||
'mt-4 mr-4 space-y-2 rounded-full h-[120px] w-[120px] flex flex-col items-center justify-center cursor-pointer'
|
||||
)}
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
import * as Tooltip from '@radix-ui/react-tooltip'
|
||||
import { PermissionAction } from '@supabase/shared-types/out/constants'
|
||||
import { useParams } from 'common'
|
||||
import { isNil } from 'lodash'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { Button, Form, IconMail, Input, Listbox, Modal } from 'ui'
|
||||
import toast from 'react-hot-toast'
|
||||
import { object, string } from 'yup'
|
||||
|
||||
import { useParams } from 'common'
|
||||
import { useOrganizationMemberInviteCreateMutation } from 'data/organizations/organization-member-invite-create-mutation'
|
||||
import type { OrganizationMember } from 'data/organizations/organization-members-query'
|
||||
import { doPermissionsCheck, useGetPermissions, useStore } from 'hooks'
|
||||
import { doPermissionsCheck, useGetPermissions } from 'hooks'
|
||||
import type { Role } from 'types'
|
||||
import { Button, Form, IconMail, Input, Listbox, Modal } from 'ui'
|
||||
|
||||
export interface InviteMemberButtonProps {
|
||||
orgId: number
|
||||
@@ -26,7 +27,6 @@ const InviteMemberButton = ({
|
||||
roles = [],
|
||||
rolesAddable = [],
|
||||
}: InviteMemberButtonProps) => {
|
||||
const { ui } = useStore()
|
||||
const { slug } = useParams()
|
||||
const [isOpen, setIsOpen] = useState(false)
|
||||
const { permissions: allPermissions } = useGetPermissions()
|
||||
@@ -60,15 +60,9 @@ const InviteMemberButton = ({
|
||||
)
|
||||
if (existingMember !== undefined) {
|
||||
if (existingMember.invited_id) {
|
||||
return ui.setNotification({
|
||||
category: 'info',
|
||||
message: 'User has already been invited to this organization',
|
||||
})
|
||||
return toast('User has already been invited to this organization')
|
||||
} else {
|
||||
return ui.setNotification({
|
||||
category: 'info',
|
||||
message: 'User is already in this organization',
|
||||
})
|
||||
return toast('User is already in this organization')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,9 +76,9 @@ const InviteMemberButton = ({
|
||||
roleId,
|
||||
})
|
||||
if (isNil(response)) {
|
||||
ui.setNotification({ category: 'error', message: 'Failed to add member' })
|
||||
toast.error('Failed to add member')
|
||||
} else {
|
||||
ui.setNotification({ category: 'success', message: 'Successfully added new member.' })
|
||||
toast.success('Successfully added new member')
|
||||
setIsOpen(!isOpen)
|
||||
resetForm({ initialValues: { ...initialValues, role: roleId } })
|
||||
}
|
||||
|
||||
@@ -1,8 +1,17 @@
|
||||
import * as Tooltip from '@radix-ui/react-tooltip'
|
||||
import { PermissionAction } from '@supabase/shared-types/out/constants'
|
||||
import { useParams } from 'common'
|
||||
import { observer } from 'mobx-react-lite'
|
||||
import { useState } from 'react'
|
||||
import toast from 'react-hot-toast'
|
||||
|
||||
import { useParams } from 'common'
|
||||
import { useOrganizationMemberDeleteMutation } from 'data/organizations/organization-member-delete-mutation'
|
||||
import { useOrganizationMemberInviteCreateMutation } from 'data/organizations/organization-member-invite-create-mutation'
|
||||
import { useOrganizationMemberInviteDeleteMutation } from 'data/organizations/organization-member-invite-delete-mutation'
|
||||
import type { OrganizationMember } from 'data/organizations/organization-members-query'
|
||||
import { usePermissionsQuery } from 'data/permissions/permissions-query'
|
||||
import { useCheckPermissions, useIsFeatureEnabled, useSelectedOrganization } from 'hooks'
|
||||
import type { Role } from 'types'
|
||||
import {
|
||||
Button,
|
||||
DropdownMenu,
|
||||
@@ -14,16 +23,7 @@ import {
|
||||
IconTrash,
|
||||
Modal,
|
||||
} from 'ui'
|
||||
|
||||
import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal'
|
||||
import { useOrganizationMemberDeleteMutation } from 'data/organizations/organization-member-delete-mutation'
|
||||
import { useOrganizationMemberInviteCreateMutation } from 'data/organizations/organization-member-invite-create-mutation'
|
||||
import { useOrganizationMemberInviteDeleteMutation } from 'data/organizations/organization-member-invite-delete-mutation'
|
||||
import type { OrganizationMember } from 'data/organizations/organization-members-query'
|
||||
import { usePermissionsQuery } from 'data/permissions/permissions-query'
|
||||
import { useCheckPermissions, useIsFeatureEnabled, useSelectedOrganization, useStore } from 'hooks'
|
||||
import type { Role } from 'types'
|
||||
import { isInviteExpired } from '../Organization.utils'
|
||||
import { useGetRolesManagementPermissions } from './TeamSettings.utils'
|
||||
|
||||
interface MemberActionsProps {
|
||||
@@ -32,9 +32,7 @@ interface MemberActionsProps {
|
||||
}
|
||||
|
||||
const MemberActions = ({ member, roles }: MemberActionsProps) => {
|
||||
const { ui } = useStore()
|
||||
const { slug } = useParams()
|
||||
|
||||
const organizationMembersDeletionEnabled = useIsFeatureEnabled('organization_members:delete')
|
||||
|
||||
const selectedOrganization = useSelectedOrganization()
|
||||
@@ -61,10 +59,7 @@ const MemberActions = ({ member, roles }: MemberActionsProps) => {
|
||||
const { mutate: deleteOrganizationMember, isLoading: isDeletingMember } =
|
||||
useOrganizationMemberDeleteMutation({
|
||||
onSuccess: () => {
|
||||
ui.setNotification({
|
||||
category: 'success',
|
||||
message: `Successfully removed ${member.primary_email}`,
|
||||
})
|
||||
toast.success(`Successfully removed ${member.primary_email}`)
|
||||
setIsDeleteModalOpen(false)
|
||||
},
|
||||
})
|
||||
@@ -72,13 +67,10 @@ const MemberActions = ({ member, roles }: MemberActionsProps) => {
|
||||
const { mutate: createOrganizationMemberInvite, isLoading: isCreatingInvite } =
|
||||
useOrganizationMemberInviteCreateMutation({
|
||||
onSuccess: () => {
|
||||
ui.setNotification({ category: 'success', message: 'Resent the invitation.' })
|
||||
toast.success('Resent the invitation.')
|
||||
},
|
||||
onError: (error) => {
|
||||
ui.setNotification({
|
||||
category: 'error',
|
||||
message: `Failed to resend invitation: ${error.message}`,
|
||||
})
|
||||
toast.error(`Failed to resend invitation: ${error.message}`)
|
||||
},
|
||||
})
|
||||
|
||||
@@ -113,10 +105,7 @@ const MemberActions = ({ member, roles }: MemberActionsProps) => {
|
||||
if (!invitedId) return console.error('Member invited ID is required')
|
||||
|
||||
await asyncDeleteMemberInvite({ slug, invitedId })
|
||||
ui.setNotification({
|
||||
category: 'success',
|
||||
message: 'Successfully revoked the invitation.',
|
||||
})
|
||||
toast.success('Successfully revoked the invitation.')
|
||||
}
|
||||
|
||||
if (!canRemoveMember || (isPendingInviteAcceptance && !canResendInvite && !canRevokeInvite)) {
|
||||
|
||||
@@ -1,8 +1,22 @@
|
||||
import * as Tooltip from '@radix-ui/react-tooltip'
|
||||
import { useParams } from 'common'
|
||||
import { observer } from 'mobx-react-lite'
|
||||
import Image from 'next/legacy/image'
|
||||
import { Fragment, useState } from 'react'
|
||||
import toast from 'react-hot-toast'
|
||||
|
||||
import { useParams } from 'common'
|
||||
import Table from 'components/to-be-cleaned/Table'
|
||||
import AlertError from 'components/ui/AlertError'
|
||||
import { GenericSkeletonLoader } from 'components/ui/ShimmeringLoader'
|
||||
import { useOrganizationMemberUpdateMutation } from 'data/organizations/organization-member-update-mutation'
|
||||
import {
|
||||
OrganizationMember,
|
||||
useOrganizationMembersQuery,
|
||||
} from 'data/organizations/organization-members-query'
|
||||
import { useOrganizationRolesQuery } from 'data/organizations/organization-roles-query'
|
||||
import { usePermissionsQuery } from 'data/permissions/permissions-query'
|
||||
import { useSelectedOrganization } from 'hooks'
|
||||
import { useProfile } from 'lib/profile'
|
||||
import {
|
||||
Badge,
|
||||
Button,
|
||||
@@ -15,19 +29,6 @@ import {
|
||||
Loading,
|
||||
Modal,
|
||||
} from 'ui'
|
||||
|
||||
import Table from 'components/to-be-cleaned/Table'
|
||||
import AlertError from 'components/ui/AlertError'
|
||||
import { GenericSkeletonLoader } from 'components/ui/ShimmeringLoader'
|
||||
import { useOrganizationMemberUpdateMutation } from 'data/organizations/organization-member-update-mutation'
|
||||
import {
|
||||
OrganizationMember,
|
||||
useOrganizationMembersQuery,
|
||||
} from 'data/organizations/organization-members-query'
|
||||
import { useOrganizationRolesQuery } from 'data/organizations/organization-roles-query'
|
||||
import { usePermissionsQuery } from 'data/permissions/permissions-query'
|
||||
import { useSelectedOrganization, useStore } from 'hooks'
|
||||
import { useProfile } from 'lib/profile'
|
||||
import { getUserDisplayName, isInviteExpired } from '../Organization.utils'
|
||||
import MemberActions from './MemberActions'
|
||||
import RolesHelperModal from './RolesHelperModal/RolesHelperModal'
|
||||
@@ -43,7 +44,6 @@ export interface MembersViewProps {
|
||||
}
|
||||
|
||||
const MembersView = ({ searchString }: MembersViewProps) => {
|
||||
const { ui } = useStore()
|
||||
const { slug } = useParams()
|
||||
const selectedOrganization = useSelectedOrganization()
|
||||
|
||||
@@ -65,18 +65,12 @@ const MembersView = ({ searchString }: MembersViewProps) => {
|
||||
const { mutate: updateOrganizationMember, isLoading } = useOrganizationMemberUpdateMutation({
|
||||
onSuccess() {
|
||||
setUserRoleChangeModalVisible(false)
|
||||
ui.setNotification({
|
||||
category: 'success',
|
||||
message: `Successfully updated role for ${getUserDisplayName(selectedMember)}`,
|
||||
})
|
||||
toast.success(`Successfully updated role for ${getUserDisplayName(selectedMember)}`)
|
||||
},
|
||||
onError(error) {
|
||||
ui.setNotification({
|
||||
category: 'error',
|
||||
message: `Failed to update role for ${getUserDisplayName(selectedMember)}: ${
|
||||
error.message
|
||||
}`,
|
||||
})
|
||||
toast.error(
|
||||
`Failed to update role for ${getUserDisplayName(selectedMember)}: ${error.message}`
|
||||
)
|
||||
},
|
||||
})
|
||||
|
||||
@@ -173,13 +167,11 @@ const MembersView = ({ searchString }: MembersViewProps) => {
|
||||
const canAddRole = rolesAddable.includes(selectedRole?.id ?? -1)
|
||||
|
||||
if (!canAddRole) {
|
||||
return ui.setNotification({
|
||||
category: 'error',
|
||||
duration: 4000,
|
||||
message: `You do not have permission to update this team member to ${
|
||||
return toast.error(
|
||||
`You do not have permission to update this team member to ${
|
||||
selectedRole!.name
|
||||
}`,
|
||||
})
|
||||
}`
|
||||
)
|
||||
}
|
||||
|
||||
setUserRoleChangeModalVisible(true)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import * as Tooltip from '@radix-ui/react-tooltip'
|
||||
import { useParams } from 'common'
|
||||
import { useState } from 'react'
|
||||
import { Button, IconSearch, Input, Modal } from 'ui'
|
||||
import toast from 'react-hot-toast'
|
||||
|
||||
import { useParams } from 'common'
|
||||
import {
|
||||
ScaffoldActionsContainer,
|
||||
ScaffoldActionsGroup,
|
||||
@@ -10,19 +10,19 @@ import {
|
||||
ScaffoldFilterAndContent,
|
||||
ScaffoldSectionContent,
|
||||
} from 'components/layouts/Scaffold'
|
||||
import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal'
|
||||
import { useOrganizationMemberDeleteMutation } from 'data/organizations/organization-member-delete-mutation'
|
||||
import { useOrganizationMembersQuery } from 'data/organizations/organization-members-query'
|
||||
import { useOrganizationRolesQuery } from 'data/organizations/organization-roles-query'
|
||||
import { usePermissionsQuery } from 'data/permissions/permissions-query'
|
||||
import { useIsFeatureEnabled, useSelectedOrganization, useStore } from 'hooks'
|
||||
import { useIsFeatureEnabled, useSelectedOrganization } from 'hooks'
|
||||
import { useProfile } from 'lib/profile'
|
||||
import { Button, IconSearch, Input, Modal } from 'ui'
|
||||
import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal'
|
||||
import InviteMemberButton from './InviteMemberButton'
|
||||
import MembersView from './MembersView'
|
||||
import { hasMultipleOwners, useGetRolesManagementPermissions } from './TeamSettings.utils'
|
||||
|
||||
const TeamSettings = () => {
|
||||
const { ui } = useStore()
|
||||
const { slug } = useParams()
|
||||
|
||||
const {
|
||||
@@ -64,10 +64,7 @@ const TeamSettings = () => {
|
||||
setIsLeaveTeamModalOpen(false)
|
||||
window?.location.replace('/') // Force reload to clear Store
|
||||
} catch (error: any) {
|
||||
ui.setNotification({
|
||||
category: 'error',
|
||||
message: `Failed to leave organization: ${error?.message}`,
|
||||
})
|
||||
toast.error(`Failed to leave organization: ${error?.message}`)
|
||||
} finally {
|
||||
setIsLeaving(false)
|
||||
}
|
||||
|
||||
@@ -1,18 +1,16 @@
|
||||
import { useParams } from 'common'
|
||||
import Link from 'next/link'
|
||||
import { useState } from 'react'
|
||||
import { Button, IconDownload, IconExternalLink } from 'ui'
|
||||
import toast from 'react-hot-toast'
|
||||
|
||||
import { useParams } from 'common'
|
||||
import { generateTypes } from 'data/projects/project-type-generation-query'
|
||||
import { useStore } from 'hooks'
|
||||
import { Button, IconDownload, IconExternalLink } from 'ui'
|
||||
import ContentSnippet from '../ContentSnippet'
|
||||
import { DOCS_CONTENT } from '../ProjectAPIDocs.constants'
|
||||
import type { ContentProps } from './Content.types'
|
||||
|
||||
const Entities = ({ language }: ContentProps) => {
|
||||
const { ui } = useStore()
|
||||
const { ref } = useParams()
|
||||
|
||||
const [isGeneratingTypes, setIsGeneratingTypes] = useState(false)
|
||||
|
||||
const onClickGenerateTypes = async () => {
|
||||
@@ -26,16 +24,9 @@ const Entities = ({ language }: ContentProps) => {
|
||||
document.body.appendChild(element)
|
||||
element.click()
|
||||
document.body.removeChild(element)
|
||||
ui.setNotification({
|
||||
category: 'success',
|
||||
message: `Successfully generated types! File is being downloaded`,
|
||||
})
|
||||
toast.success(`Successfully generated types! File is being downloaded`)
|
||||
} catch (error: any) {
|
||||
ui.setNotification({
|
||||
error,
|
||||
category: 'error',
|
||||
message: `Failed to generate types: ${error.message}`,
|
||||
})
|
||||
toast.error(`Failed to generate types: ${error.message}`)
|
||||
} finally {
|
||||
setIsGeneratingTypes(false)
|
||||
}
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
import { useParams } from 'common'
|
||||
import { useEffect, useState } from 'react'
|
||||
import toast from 'react-hot-toast'
|
||||
|
||||
import { useParams } from 'common'
|
||||
import { useSqlTitleGenerateMutation } from 'data/ai/sql-title-mutation'
|
||||
import type { SqlSnippet } from 'data/content/sql-snippets-query'
|
||||
import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query'
|
||||
import { isError } from 'data/utils/error-check'
|
||||
import { useSelectedOrganization, useStore } from 'hooks'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { useSelectedOrganization } from 'hooks'
|
||||
import { useSqlEditorStateSnapshot } from 'state/sql-editor'
|
||||
import { AiIconAnimation, Button, Form, Input, Modal } from 'ui'
|
||||
import { subscriptionHasHipaaAddon } from '../Billing/Subscription/Subscription.utils'
|
||||
import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query'
|
||||
|
||||
export interface RenameQueryModalProps {
|
||||
snippet: SqlSnippet
|
||||
@@ -18,7 +19,6 @@ export interface RenameQueryModalProps {
|
||||
}
|
||||
|
||||
const RenameQueryModal = ({ snippet, visible, onCancel, onComplete }: RenameQueryModalProps) => {
|
||||
const { ui } = useStore()
|
||||
const { ref } = useParams()
|
||||
const organization = useSelectedOrganization()
|
||||
const snap = useSqlEditorStateSnapshot()
|
||||
@@ -52,11 +52,7 @@ const RenameQueryModal = ({ snippet, visible, onCancel, onComplete }: RenameQuer
|
||||
if (onComplete) onComplete()
|
||||
return Promise.resolve()
|
||||
} catch (error: any) {
|
||||
ui.setNotification({
|
||||
error,
|
||||
category: 'error',
|
||||
message: `Failed to rename query: ${error.message}`,
|
||||
})
|
||||
toast.error(`Failed to rename query: ${error.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,10 +101,7 @@ const RenameQueryModal = ({ snippet, visible, onCancel, onComplete }: RenameQuer
|
||||
}
|
||||
} catch (error: unknown) {
|
||||
if (isError(error)) {
|
||||
ui.setNotification({
|
||||
category: 'error',
|
||||
message: `Failed to rename query: ${error.message}`,
|
||||
})
|
||||
toast.error(`Failed to rename query: ${error.message}`)
|
||||
}
|
||||
}
|
||||
}}
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
import { useTelemetryProps } from 'common'
|
||||
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import { useStore } from 'hooks'
|
||||
import { copyToClipboard } from 'lib/helpers'
|
||||
import Telemetry from 'lib/telemetry'
|
||||
import { compact, isObject, isString, map } from 'lodash'
|
||||
// @ts-ignore
|
||||
import MarkdownTable from 'markdown-table'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useMemo, useRef } from 'react'
|
||||
import { CSVLink } from 'react-csv'
|
||||
import toast from 'react-hot-toast'
|
||||
|
||||
import { useTelemetryProps } from 'common'
|
||||
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import { copyToClipboard } from 'lib/helpers'
|
||||
import Telemetry from 'lib/telemetry'
|
||||
import { useSqlEditorStateSnapshot } from 'state/sql-editor'
|
||||
import {
|
||||
Button,
|
||||
@@ -18,20 +21,16 @@ import {
|
||||
IconClipboard,
|
||||
IconDownload,
|
||||
} from 'ui'
|
||||
// @ts-ignore
|
||||
import MarkdownTable from 'markdown-table'
|
||||
|
||||
export type ResultsDropdownProps = {
|
||||
id: string
|
||||
isExecuting?: boolean
|
||||
}
|
||||
|
||||
const ResultsDropdown = ({ id, isExecuting }: ResultsDropdownProps) => {
|
||||
const ResultsDropdown = ({ id }: ResultsDropdownProps) => {
|
||||
const { project } = useProjectContext()
|
||||
const snap = useSqlEditorStateSnapshot()
|
||||
const telemetryProps = useTelemetryProps()
|
||||
const result = snap.results?.[id]?.[0] ?? undefined
|
||||
const { ui } = useStore()
|
||||
const csvRef = useRef<CSVLink & HTMLAnchorElement & { link: HTMLAnchorElement }>(null)
|
||||
const router = useRouter()
|
||||
|
||||
@@ -94,7 +93,7 @@ const ResultsDropdown = ({ id, isExecuting }: ResultsDropdownProps) => {
|
||||
const markdownData = MarkdownTable(table)
|
||||
|
||||
copyToClipboard(markdownData, () => {
|
||||
ui.setNotification({ category: 'success', message: 'Copied results to clipboard' })
|
||||
toast.success('Copied results to clipboard')
|
||||
Telemetry.sendEvent(
|
||||
{ category: 'sql_editor', action: 'sql_copy_as_markdown', label: '' },
|
||||
telemetryProps,
|
||||
@@ -111,7 +110,7 @@ const ResultsDropdown = ({ id, isExecuting }: ResultsDropdownProps) => {
|
||||
if (result.rows.length == 0) return 'results is empty'
|
||||
|
||||
copyToClipboard(JSON.stringify(result.rows, null, 2), () => {
|
||||
ui.setNotification({ category: 'success', message: 'Copied results to clipboard' })
|
||||
toast.success('Copied results to clipboard')
|
||||
Telemetry.sendEvent(
|
||||
{ category: 'sql_editor', action: 'sql_copy_as_json', label: '' },
|
||||
telemetryProps,
|
||||
|
||||
@@ -54,7 +54,7 @@ const UtilityPanel = ({
|
||||
)}
|
||||
</div>
|
||||
<div className="flex gap-1 h-full">
|
||||
{result && result.rows && <ResultsDropdown id={id} isExecuting={isExecuting} />}
|
||||
{result && result.rows && <ResultsDropdown id={id} />}
|
||||
<UtilityActions
|
||||
id={id}
|
||||
isExecuting={isExecuting}
|
||||
|
||||
@@ -6,6 +6,15 @@ import {
|
||||
JwtSecretUpdateStatus,
|
||||
} from '@supabase/shared-types/out/events'
|
||||
import { Dispatch, SetStateAction, useState } from 'react'
|
||||
import toast from 'react-hot-toast'
|
||||
|
||||
import { useParams } from 'common'
|
||||
import Panel from 'components/ui/Panel'
|
||||
import { useJwtSecretUpdateMutation } from 'data/config/jwt-secret-update-mutation'
|
||||
import { useJwtSecretUpdatingStatusQuery } from 'data/config/jwt-secret-updating-status-query'
|
||||
import { useProjectPostgrestConfigQuery } from 'data/config/project-postgrest-config-query'
|
||||
import { useCheckPermissions } from 'hooks'
|
||||
import { uuidv4 } from 'lib/helpers'
|
||||
import {
|
||||
Alert,
|
||||
AlertDescription_Shadcn_,
|
||||
@@ -29,22 +38,13 @@ import {
|
||||
Input,
|
||||
Modal,
|
||||
} from 'ui'
|
||||
|
||||
import { useParams } from 'common/hooks'
|
||||
import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal'
|
||||
import Panel from 'components/ui/Panel'
|
||||
import { useJwtSecretUpdateMutation } from 'data/config/jwt-secret-update-mutation'
|
||||
import { useJwtSecretUpdatingStatusQuery } from 'data/config/jwt-secret-updating-status-query'
|
||||
import { useProjectPostgrestConfigQuery } from 'data/config/project-postgrest-config-query'
|
||||
import { useCheckPermissions, useStore } from 'hooks'
|
||||
import { uuidv4 } from 'lib/helpers'
|
||||
import {
|
||||
JWT_SECRET_UPDATE_ERROR_MESSAGES,
|
||||
JWT_SECRET_UPDATE_PROGRESS_MESSAGES,
|
||||
} from './API.constants'
|
||||
|
||||
const JWTSettings = () => {
|
||||
const { ui } = useStore()
|
||||
const { ref: projectRef } = useParams()
|
||||
|
||||
const [customToken, setCustomToken] = useState<string>('')
|
||||
@@ -83,11 +83,9 @@ const JWTSettings = () => {
|
||||
try {
|
||||
await updateJwt({ projectRef, jwtSecret: jwt_secret, changeTrackingId: trackingId })
|
||||
setModalVisibility(false)
|
||||
ui.setNotification({
|
||||
category: 'info',
|
||||
message:
|
||||
'Successfully submitted JWT secret update request. Please wait while your project is updated.',
|
||||
})
|
||||
toast(
|
||||
'Successfully submitted JWT secret update request. Please wait while your project is updated.'
|
||||
)
|
||||
} catch (error) {}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,8 +2,9 @@ import { PermissionAction } from '@supabase/shared-types/out/constants'
|
||||
import { indexOf } from 'lodash'
|
||||
import { observer } from 'mobx-react-lite'
|
||||
import { useEffect } from 'react'
|
||||
import toast from 'react-hot-toast'
|
||||
|
||||
import { useParams } from 'common/hooks'
|
||||
import { useParams } from 'common'
|
||||
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import {
|
||||
FormActions,
|
||||
@@ -12,17 +13,15 @@ import {
|
||||
FormSectionContent,
|
||||
FormSectionLabel,
|
||||
} from 'components/ui/Forms'
|
||||
import MultiSelect from 'ui-patterns/MultiSelect'
|
||||
import { useProjectPostgrestConfigQuery } from 'data/config/project-postgrest-config-query'
|
||||
import { useProjectPostgrestConfigUpdateMutation } from 'data/config/project-postgrest-config-update-mutation'
|
||||
import { useSchemasQuery } from 'data/database/schemas-query'
|
||||
import { useCheckPermissions, useStore } from 'hooks'
|
||||
import { useCheckPermissions } from 'hooks'
|
||||
import { Form, IconAlertCircle, Input, InputNumber } from 'ui'
|
||||
import MultiSelect from 'ui-patterns/MultiSelect'
|
||||
|
||||
const PostgrestConfig = () => {
|
||||
const { ref: projectRef } = useParams()
|
||||
const { ui } = useStore()
|
||||
|
||||
const { project } = useProjectContext()
|
||||
const { data: schemas } = useSchemasQuery({
|
||||
projectRef: project?.ref,
|
||||
@@ -33,7 +32,7 @@ const PostgrestConfig = () => {
|
||||
const { mutate: updatePostgrestConfig, isLoading: isUpdating } =
|
||||
useProjectPostgrestConfigUpdateMutation({
|
||||
onSuccess: () => {
|
||||
ui.setNotification({ category: 'success', message: 'Successfully saved settings' })
|
||||
toast.success('Successfully saved settings')
|
||||
},
|
||||
})
|
||||
const canUpdatePostgrestConfig = useCheckPermissions(
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { JwtSecretUpdateError, JwtSecretUpdateStatus } from '@supabase/shared-types/out/events'
|
||||
import { useQueryClient } from '@tanstack/react-query'
|
||||
import { useParams } from 'common'
|
||||
import { useEffect, useRef } from 'react'
|
||||
import { Badge, IconAlertCircle, Input } from 'ui'
|
||||
import toast from 'react-hot-toast'
|
||||
|
||||
import { useParams } from 'common'
|
||||
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import DatabaseSelector from 'components/ui/DatabaseSelector'
|
||||
import Panel from 'components/ui/Panel'
|
||||
@@ -15,15 +15,14 @@ import { useProjectApiQuery } from 'data/config/project-api-query'
|
||||
import { useCustomDomainsQuery } from 'data/custom-domains/custom-domains-query'
|
||||
import { useLoadBalancersQuery } from 'data/read-replicas/load-balancers-query'
|
||||
import { useReadReplicasQuery } from 'data/read-replicas/replicas-query'
|
||||
import { useStore } from 'hooks'
|
||||
import { PROJECT_STATUS } from 'lib/constants'
|
||||
import { useDatabaseSelectorStateSnapshot } from 'state/database-selector'
|
||||
import { Badge, IconAlertCircle, Input } from 'ui'
|
||||
import { JWT_SECRET_UPDATE_ERROR_MESSAGES } from './API.constants'
|
||||
import JWTSettings from './JWTSettings'
|
||||
import PostgrestConfig from './PostgrestConfig'
|
||||
|
||||
const ServiceList = () => {
|
||||
const { ui } = useStore()
|
||||
const client = useQueryClient()
|
||||
const { project, isLoading } = useProjectContext()
|
||||
const { ref: projectRef, source } = useParams()
|
||||
@@ -74,14 +73,10 @@ const ServiceList = () => {
|
||||
client.invalidateQueries(configKeys.api(projectRef))
|
||||
client.invalidateQueries(configKeys.settings(projectRef))
|
||||
client.invalidateQueries(configKeys.postgrest(projectRef))
|
||||
|
||||
ui.setNotification({ category: 'success', message: 'Successfully updated JWT secret' })
|
||||
toast.success('Successfully updated JWT secret')
|
||||
break
|
||||
case Failed:
|
||||
ui.setNotification({
|
||||
category: 'error',
|
||||
message: `JWT secret update failed: ${jwtSecretUpdateErrorMessage}`,
|
||||
})
|
||||
toast.error(`JWT secret update failed: ${jwtSecretUpdateErrorMessage}`)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
import Link from 'next/link'
|
||||
import { useState, useEffect } from 'react'
|
||||
import { useParams } from 'common/hooks'
|
||||
import { useStore } from 'hooks'
|
||||
import { useEffect, useState } from 'react'
|
||||
import toast from 'react-hot-toast'
|
||||
import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal'
|
||||
|
||||
import { useParams } from 'common'
|
||||
import { FormHeader, FormPanel } from 'components/ui/Forms'
|
||||
import { useBannedIPsDeleteMutation } from 'data/banned-ips/banned-ips-delete-mutations'
|
||||
import { useBannedIPsQuery } from 'data/banned-ips/banned-ips-query'
|
||||
import { BASE_PATH } from 'lib/constants'
|
||||
import {
|
||||
AlertDescription_Shadcn_,
|
||||
AlertTitle_Shadcn_,
|
||||
Alert_Shadcn_,
|
||||
Badge,
|
||||
Button,
|
||||
IconAlertTriangle,
|
||||
IconExternalLink,
|
||||
IconGlobe,
|
||||
Modal,
|
||||
Badge,
|
||||
} from 'ui'
|
||||
import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal'
|
||||
|
||||
import { useBannedIPsQuery } from 'data/banned-ips/banned-ips-query'
|
||||
import { useBannedIPsDeleteMutation } from 'data/banned-ips/banned-ips-delete-mutations'
|
||||
import { BASE_PATH } from 'lib/constants'
|
||||
|
||||
const BannedIPs = () => {
|
||||
const { ref } = useParams()
|
||||
@@ -27,24 +27,17 @@ const BannedIPs = () => {
|
||||
projectRef: ref,
|
||||
})
|
||||
|
||||
const { ui } = useStore()
|
||||
const [showUnban, setShowUnban] = useState(false)
|
||||
const [confirmingIP, setConfirmingIP] = useState<string | null>(null) // Track the IP being confirmed for unban
|
||||
|
||||
const { mutate: unbanIPs, isLoading: isUnbanning } = useBannedIPsDeleteMutation({
|
||||
onSuccess: () => {
|
||||
ui.setNotification({
|
||||
category: 'success',
|
||||
message: 'IP address successfully unbanned',
|
||||
})
|
||||
toast.success('IP address successfully unbanned')
|
||||
setSelectedIPToUnban(null) // Reset the selected IP for unban
|
||||
setShowUnban(false)
|
||||
},
|
||||
onError: (error) => {
|
||||
ui.setNotification({
|
||||
category: 'error',
|
||||
message: `Failed to unban IP: ${error?.message}`,
|
||||
})
|
||||
toast.error(`Failed to unban IP: ${error?.message}`)
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
@@ -3,23 +3,23 @@ import { PermissionAction } from '@supabase/shared-types/out/constants'
|
||||
import dayjs from 'dayjs'
|
||||
import Link from 'next/link'
|
||||
import { useState } from 'react'
|
||||
import { Alert, Button, Form, InputNumber, Modal } from 'ui'
|
||||
import toast from 'react-hot-toast'
|
||||
import { number, object } from 'yup'
|
||||
|
||||
import { useParams } from 'common/hooks'
|
||||
import { useParams } from 'common'
|
||||
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import { FormHeader } from 'components/ui/Forms'
|
||||
import Panel from 'components/ui/Panel'
|
||||
import { useProjectDiskResizeMutation } from 'data/config/project-disk-resize-mutation'
|
||||
import { useCheckPermissions, useSelectedOrganization, useStore } from 'hooks'
|
||||
import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query'
|
||||
import { useCheckPermissions, useSelectedOrganization } from 'hooks'
|
||||
import { Alert, Button, Form, InputNumber, Modal } from 'ui'
|
||||
|
||||
export interface DiskSizeConfigurationProps {
|
||||
disabled?: boolean
|
||||
}
|
||||
|
||||
const DiskSizeConfiguration = ({ disabled = false }: DiskSizeConfigurationProps) => {
|
||||
const { ui } = useStore()
|
||||
const { project } = useProjectContext()
|
||||
const organization = useSelectedOrganization()
|
||||
const { ref: projectRef } = useParams()
|
||||
@@ -46,10 +46,7 @@ const DiskSizeConfiguration = ({ disabled = false }: DiskSizeConfigurationProps)
|
||||
const { mutate: updateProjectUsage, isLoading: isUpdatingDiskSize } =
|
||||
useProjectDiskResizeMutation({
|
||||
onSuccess: (res, variables) => {
|
||||
ui.setNotification({
|
||||
category: 'success',
|
||||
message: `Successfully updated disk size to ${variables.volumeSize} GB`,
|
||||
})
|
||||
toast.success(`Successfully updated disk size to ${variables.volumeSize} GB`)
|
||||
setShowResetDbPass(false)
|
||||
},
|
||||
})
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import * as Tooltip from '@radix-ui/react-tooltip'
|
||||
import { PermissionAction } from '@supabase/shared-types/out/constants'
|
||||
import { useParams } from 'common'
|
||||
import Link from 'next/link'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { Alert, Button, IconDownload, IconExternalLink, IconLoader, Toggle } from 'ui'
|
||||
import toast from 'react-hot-toast'
|
||||
|
||||
import { useParams } from 'common'
|
||||
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import {
|
||||
FormHeader,
|
||||
@@ -16,10 +16,10 @@ import {
|
||||
import { useProjectSettingsQuery } from 'data/config/project-settings-query'
|
||||
import { useSSLEnforcementQuery } from 'data/ssl-enforcement/ssl-enforcement-query'
|
||||
import { useSSLEnforcementUpdateMutation } from 'data/ssl-enforcement/ssl-enforcement-update-mutation'
|
||||
import { useCheckPermissions, useStore } from 'hooks'
|
||||
import { useCheckPermissions } from 'hooks'
|
||||
import { Alert, Button, IconDownload, IconExternalLink, IconLoader, Toggle } from 'ui'
|
||||
|
||||
const SSLConfiguration = () => {
|
||||
const { ui } = useStore()
|
||||
const { ref } = useParams()
|
||||
const [isEnforced, setIsEnforced] = useState(false)
|
||||
|
||||
@@ -34,18 +34,11 @@ const SSLConfiguration = () => {
|
||||
const { mutate: updateSSLEnforcement, isLoading: isSubmitting } = useSSLEnforcementUpdateMutation(
|
||||
{
|
||||
onSuccess: () => {
|
||||
ui.setNotification({
|
||||
category: 'success',
|
||||
message: 'Successfully updated SSL configuration',
|
||||
})
|
||||
toast.success('Successfully updated SSL configuration')
|
||||
},
|
||||
onError: (error) => {
|
||||
setIsEnforced(initialIsEnforced)
|
||||
ui.setNotification({
|
||||
error,
|
||||
category: 'error',
|
||||
message: `Failed to update SSL enforcement: ${error.message}`,
|
||||
})
|
||||
toast.error(`Failed to update SSL enforcement: ${error.message}`)
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
+6
-9
@@ -3,21 +3,21 @@ import { PermissionAction } from '@supabase/shared-types/out/constants'
|
||||
import { useQueryClient } from '@tanstack/react-query'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useState } from 'react'
|
||||
import { Button, IconPause, Modal } from 'ui'
|
||||
import toast from 'react-hot-toast'
|
||||
|
||||
import {
|
||||
useIsProjectActive,
|
||||
useProjectContext,
|
||||
} from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal'
|
||||
import { useProjectPauseMutation } from 'data/projects/project-pause-mutation'
|
||||
import { setProjectStatus } from 'data/projects/projects-query'
|
||||
import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query'
|
||||
import { useCheckPermissions, useSelectedOrganization, useStore } from 'hooks'
|
||||
import { useCheckPermissions, useSelectedOrganization } from 'hooks'
|
||||
import { PROJECT_STATUS } from 'lib/constants'
|
||||
import { Button, IconPause, Modal } from 'ui'
|
||||
import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal'
|
||||
|
||||
const PauseProjectButton = () => {
|
||||
const { ui } = useStore()
|
||||
const router = useRouter()
|
||||
const queryClient = useQueryClient()
|
||||
const { project } = useProjectContext()
|
||||
@@ -38,17 +38,14 @@ const PauseProjectButton = () => {
|
||||
const { mutate: pauseProject, isLoading: isPausing } = useProjectPauseMutation({
|
||||
onSuccess: (res, variables) => {
|
||||
setProjectStatus(queryClient, variables.ref, PROJECT_STATUS.PAUSING)
|
||||
ui.setNotification({ category: 'success', message: 'Pausing project...' })
|
||||
toast.success('Pausing project...')
|
||||
router.push(`/project/${projectRef}`)
|
||||
},
|
||||
})
|
||||
|
||||
const requestPauseProject = () => {
|
||||
if (!canPauseProject) {
|
||||
return ui.setNotification({
|
||||
category: 'error',
|
||||
message: 'You do not have the required permissions to pause this project',
|
||||
})
|
||||
return toast.error('You do not have the required permissions to pause this project')
|
||||
}
|
||||
pauseProject({ ref: projectRef })
|
||||
}
|
||||
|
||||
+9
-10
@@ -2,6 +2,13 @@ import { useQueryClient } from '@tanstack/react-query'
|
||||
import Link from 'next/link'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useState } from 'react'
|
||||
import toast from 'react-hot-toast'
|
||||
|
||||
import { useParams } from 'common'
|
||||
import { useProjectUpgradeEligibilityQuery } from 'data/config/project-upgrade-eligibility-query'
|
||||
import { useProjectUpgradeMutation } from 'data/projects/project-upgrade-mutation'
|
||||
import { setProjectStatus } from 'data/projects/projects-query'
|
||||
import { PROJECT_STATUS } from 'lib/constants'
|
||||
import {
|
||||
AlertDescription_Shadcn_,
|
||||
AlertTitle_Shadcn_,
|
||||
@@ -14,16 +21,8 @@ import {
|
||||
Modal,
|
||||
} from 'ui'
|
||||
|
||||
import { useParams } from 'common/hooks'
|
||||
import { useProjectUpgradeEligibilityQuery } from 'data/config/project-upgrade-eligibility-query'
|
||||
import { useProjectUpgradeMutation } from 'data/projects/project-upgrade-mutation'
|
||||
import { setProjectStatus } from 'data/projects/projects-query'
|
||||
import { useStore } from 'hooks'
|
||||
import { PROJECT_STATUS } from 'lib/constants'
|
||||
|
||||
const ProjectUpgradeAlert = () => {
|
||||
const router = useRouter()
|
||||
const { ui } = useStore()
|
||||
const { ref } = useParams()
|
||||
const queryClient = useQueryClient()
|
||||
const [showUpgradeModal, setShowUpgradeModal] = useState(false)
|
||||
@@ -40,13 +39,13 @@ const ProjectUpgradeAlert = () => {
|
||||
const { mutate: upgradeProject, isLoading: isUpgrading } = useProjectUpgradeMutation({
|
||||
onSuccess: (res, variables) => {
|
||||
setProjectStatus(queryClient, variables.ref, PROJECT_STATUS.UPGRADING)
|
||||
ui.setNotification({ category: 'success', message: 'Upgrading project' })
|
||||
toast.success('Upgrading project')
|
||||
router.push(`/project/${variables.ref}?upgradeInitiated=true`)
|
||||
},
|
||||
})
|
||||
|
||||
const onConfirmUpgrade = async (values: any) => {
|
||||
if (!ref) return ui.setNotification({ category: 'error', message: 'Project ref not found' })
|
||||
if (!ref) return toast.error('Project ref not found')
|
||||
upgradeProject({ ref, target_version: values.version })
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { useState } from 'react'
|
||||
import { Modal } from 'ui'
|
||||
import toast from 'react-hot-toast'
|
||||
|
||||
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import { useVaultSecretDeleteMutation } from 'data/vault/vault-secret-delete-mutation'
|
||||
import { useStore } from 'hooks'
|
||||
import type { VaultSecret } from 'types'
|
||||
import { Modal } from 'ui'
|
||||
|
||||
interface DeleteSecretModalProps {
|
||||
selectedSecret: VaultSecret | undefined
|
||||
@@ -12,7 +12,6 @@ interface DeleteSecretModalProps {
|
||||
}
|
||||
|
||||
const DeleteSecretModal = ({ selectedSecret, onClose }: DeleteSecretModalProps) => {
|
||||
const { ui } = useStore()
|
||||
const { project } = useProjectContext()
|
||||
|
||||
const [isDeleting, setIsDeleting] = useState(false)
|
||||
@@ -32,16 +31,9 @@ const DeleteSecretModal = ({ selectedSecret, onClose }: DeleteSecretModalProps)
|
||||
id: selectedSecret.id,
|
||||
})
|
||||
if (res.error) {
|
||||
ui.setNotification({
|
||||
error: res.error,
|
||||
category: 'error',
|
||||
message: `Failed to delete secret: ${res.error.message}`,
|
||||
})
|
||||
toast.error(`Failed to delete secret: ${res.error.message}`)
|
||||
} else {
|
||||
ui.setNotification({
|
||||
category: 'success',
|
||||
message: `Successfully deleted secret ${selectedSecret.name}`,
|
||||
})
|
||||
toast.success(`Successfully deleted secret ${selectedSecret.name}`)
|
||||
onClose()
|
||||
}
|
||||
setIsDeleting(false)
|
||||
|
||||
@@ -1,23 +1,22 @@
|
||||
import * as Tooltip from '@radix-ui/react-tooltip'
|
||||
import { PermissionAction } from '@supabase/shared-types/out/constants'
|
||||
import { useParams } from 'common'
|
||||
import { observer } from 'mobx-react-lite'
|
||||
import { useTheme } from 'next-themes'
|
||||
import Link from 'next/link'
|
||||
import { useState } from 'react'
|
||||
import toast from 'react-hot-toast'
|
||||
import { Button, IconExternalLink } from 'ui'
|
||||
|
||||
import { useParams } from 'common'
|
||||
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import { useDatabaseExtensionEnableMutation } from 'data/database-extensions/database-extension-enable-mutation'
|
||||
import { useDatabaseExtensionsQuery } from 'data/database-extensions/database-extensions-query'
|
||||
import { executeSql } from 'data/sql/execute-sql-query'
|
||||
import { useCheckPermissions, useStore } from 'hooks'
|
||||
import { useCheckPermissions } from 'hooks'
|
||||
import { BASE_PATH } from 'lib/constants'
|
||||
import { Button, IconExternalLink } from 'ui'
|
||||
|
||||
const VaultToggle = () => {
|
||||
const { ref } = useParams()
|
||||
const { ui } = useStore()
|
||||
const { resolvedTheme } = useTheme()
|
||||
const { project } = useProjectContext()
|
||||
const [isEnabling, setIsEnabling] = useState(false)
|
||||
@@ -54,11 +53,7 @@ const VaultToggle = () => {
|
||||
})
|
||||
} catch (createSchemaError: any) {
|
||||
setIsEnabling(false)
|
||||
return ui.setNotification({
|
||||
error: createSchemaError,
|
||||
category: 'error',
|
||||
message: `Failed to create schema: ${createSchemaError.message}`,
|
||||
})
|
||||
return toast.error(`Failed to create schema: ${createSchemaError.message}`)
|
||||
}
|
||||
|
||||
enableExtension({
|
||||
|
||||
@@ -1,40 +1,33 @@
|
||||
import HCaptcha from '@hcaptcha/react-hcaptcha'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useRef, useState } from 'react'
|
||||
import { Button, Form, Input } from 'ui'
|
||||
import toast from 'react-hot-toast'
|
||||
import { object, string } from 'yup'
|
||||
|
||||
import { useResetPasswordMutation } from 'data/misc/reset-password-mutation'
|
||||
import { useStore } from 'hooks'
|
||||
import { BASE_PATH } from 'lib/constants'
|
||||
import { Button, Form, Input } from 'ui'
|
||||
|
||||
const forgotPasswordSchema = object({
|
||||
email: string().email('Must be a valid email').required('Email is required'),
|
||||
})
|
||||
|
||||
const ForgotPasswordForm = () => {
|
||||
const { ui } = useStore()
|
||||
const router = useRouter()
|
||||
|
||||
const [captchaToken, setCaptchaToken] = useState<string | null>(null)
|
||||
const captchaRef = useRef<HCaptcha>(null)
|
||||
const [captchaToken, setCaptchaToken] = useState<string | null>(null)
|
||||
|
||||
const { mutate: resetPassword, isLoading } = useResetPasswordMutation({
|
||||
onSuccess: async () => {
|
||||
ui.setNotification({
|
||||
category: 'success',
|
||||
message: `If you registered using your email and password, you will receive a password reset email.`,
|
||||
})
|
||||
toast.success(
|
||||
`If you registered using your email and password, you will receive a password reset email.`
|
||||
)
|
||||
await router.push('/sign-in')
|
||||
},
|
||||
onError: (error) => {
|
||||
setCaptchaToken(null)
|
||||
captchaRef.current?.resetCaptcha()
|
||||
|
||||
ui.setNotification({
|
||||
category: 'error',
|
||||
message: `Failed to send reset email: ${error.message}`,
|
||||
})
|
||||
toast.error(`Failed to send reset email: ${error.message}`)
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import { useRouter } from 'next/router'
|
||||
import toast from 'react-hot-toast'
|
||||
|
||||
import { useStore } from 'hooks'
|
||||
import { auth } from 'lib/gotrue'
|
||||
import { passwordSchema } from 'lib/schemas'
|
||||
import { useRouter } from 'next/router'
|
||||
import { Button, Form, Input } from 'ui'
|
||||
|
||||
const ResetPasswordForm = () => {
|
||||
@@ -17,22 +19,13 @@ const ResetPasswordForm = () => {
|
||||
const { error } = await auth.updateUser({ password })
|
||||
|
||||
if (!error) {
|
||||
ui.setNotification({
|
||||
id: toastId,
|
||||
category: 'success',
|
||||
message: `Password saved successfully!`,
|
||||
})
|
||||
toast.success('Password saved successfully!', { id: toastId })
|
||||
|
||||
// logout all other sessions after changing password
|
||||
await auth.signOut({ scope: 'others' })
|
||||
|
||||
await router.push('/projects')
|
||||
} else {
|
||||
ui.setNotification({
|
||||
id: toastId,
|
||||
category: 'error',
|
||||
message: error.message,
|
||||
})
|
||||
toast.error(error.message, { id: toastId })
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import { useQueryClient } from '@tanstack/react-query'
|
||||
import Link from 'next/link'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { Button, Form, IconLock, Input } from 'ui'
|
||||
import toast from 'react-hot-toast'
|
||||
import { object, string } from 'yup'
|
||||
|
||||
import { useTelemetryProps } from 'common'
|
||||
@@ -16,6 +16,7 @@ import { useStore } from 'hooks'
|
||||
import { useSignOut } from 'lib/auth'
|
||||
import { getReturnToPath } from 'lib/gotrue'
|
||||
import Telemetry from 'lib/telemetry'
|
||||
import { Button, Form, IconLock, Input } from 'ui'
|
||||
|
||||
const signInSchema = object({
|
||||
code: string().required('MFA Code is required'),
|
||||
@@ -69,27 +70,17 @@ const SignInMfaForm = () => {
|
||||
{ factorId: selectedFactor.id, code, refreshFactors: false },
|
||||
{
|
||||
onSuccess: async () => {
|
||||
ui.setNotification({
|
||||
id: toastId,
|
||||
category: 'success',
|
||||
message: `Signed in successfully!`,
|
||||
})
|
||||
|
||||
toast.success('Signed in successfully!', { id: toastId })
|
||||
Telemetry.sendEvent(
|
||||
{ category: 'account', action: 'sign_in', label: '' },
|
||||
telemetryProps,
|
||||
router
|
||||
)
|
||||
await queryClient.resetQueries()
|
||||
|
||||
router.push(getReturnToPath())
|
||||
},
|
||||
onError: (error) => {
|
||||
ui.setNotification({
|
||||
id: toastId,
|
||||
category: 'error',
|
||||
message: (error as AuthError).message,
|
||||
})
|
||||
toast.error((error as AuthError).message, { id: toastId })
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
@@ -4,6 +4,7 @@ import { useStore } from 'hooks'
|
||||
import { BASE_PATH } from 'lib/constants'
|
||||
import { auth, buildPathWithParams } from 'lib/gotrue'
|
||||
import { useRef, useState } from 'react'
|
||||
import toast from 'react-hot-toast'
|
||||
import { Button, Form, Input } from 'ui'
|
||||
import { object, string } from 'yup'
|
||||
|
||||
@@ -57,12 +58,7 @@ const SignInSSOForm = () => {
|
||||
} else {
|
||||
setCaptchaToken(null)
|
||||
captchaRef.current?.resetCaptcha()
|
||||
|
||||
ui.setNotification({
|
||||
id: toastId,
|
||||
category: 'error',
|
||||
message: error.message,
|
||||
})
|
||||
toast.error(error.message, { id: toastId })
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import HCaptcha from '@hcaptcha/react-hcaptcha'
|
||||
import { useRef, useState } from 'react'
|
||||
import { Alert, Button, Form, IconEye, IconEyeOff, Input } from 'ui'
|
||||
import toast from 'react-hot-toast'
|
||||
import * as yup from 'yup'
|
||||
|
||||
import { useSignUpMutation } from 'data/misc/signup-mutation'
|
||||
import { useStore } from 'hooks'
|
||||
import { BASE_PATH } from 'lib/constants'
|
||||
import { passwordSchema } from 'lib/schemas'
|
||||
import { Alert, Button, Form, IconEye, IconEyeOff, Input } from 'ui'
|
||||
import PasswordConditionsHelper from './PasswordConditionsHelper'
|
||||
|
||||
const signUpSchema = passwordSchema.shape({
|
||||
@@ -14,7 +14,6 @@ const signUpSchema = passwordSchema.shape({
|
||||
})
|
||||
|
||||
const SignUpForm = () => {
|
||||
const { ui } = useStore()
|
||||
const captchaRef = useRef<HCaptcha>(null)
|
||||
const [showConditions, setShowConditions] = useState(false)
|
||||
const [isSubmitted, setIsSubmitted] = useState(false)
|
||||
@@ -23,19 +22,13 @@ const SignUpForm = () => {
|
||||
|
||||
const { mutate: signup, isLoading: isSigningUp } = useSignUpMutation({
|
||||
onSuccess: () => {
|
||||
ui.setNotification({
|
||||
category: 'success',
|
||||
message: `Signed up successfully!`,
|
||||
})
|
||||
toast.success(`Signed up successfully!`)
|
||||
setIsSubmitted(true)
|
||||
},
|
||||
onError: (error) => {
|
||||
setCaptchaToken(null)
|
||||
captchaRef.current?.resetCaptcha()
|
||||
ui.setNotification({
|
||||
category: 'error',
|
||||
message: `Failed to sign up: ${error.message}`,
|
||||
})
|
||||
toast.error(`Failed to sign up: ${error.message}`)
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
@@ -1,7 +1,17 @@
|
||||
import clsx from 'clsx'
|
||||
import Link from 'next/link'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useEffect, useState } from 'react'
|
||||
import toast from 'react-hot-toast'
|
||||
|
||||
import { useParams } from 'common'
|
||||
import { StorageSizeUnits } from 'components/to-be-cleaned/Storage/StorageSettings/StorageSettings.constants'
|
||||
import {
|
||||
convertFromBytes,
|
||||
convertToBytes,
|
||||
} from 'components/to-be-cleaned/Storage/StorageSettings/StorageSettings.utils'
|
||||
import { useProjectStorageConfigQuery } from 'data/config/project-storage-config-query'
|
||||
import { useBucketCreateMutation } from 'data/storage/bucket-create-mutation'
|
||||
import { IS_PLATFORM } from 'lib/constants'
|
||||
import {
|
||||
Alert,
|
||||
Button,
|
||||
@@ -12,35 +22,21 @@ import {
|
||||
Listbox,
|
||||
Modal,
|
||||
Toggle,
|
||||
cn,
|
||||
} from 'ui'
|
||||
|
||||
import { useParams } from 'common'
|
||||
import { StorageSizeUnits } from 'components/to-be-cleaned/Storage/StorageSettings/StorageSettings.constants'
|
||||
import {
|
||||
convertFromBytes,
|
||||
convertToBytes,
|
||||
} from 'components/to-be-cleaned/Storage/StorageSettings/StorageSettings.utils'
|
||||
import { useProjectStorageConfigQuery } from 'data/config/project-storage-config-query'
|
||||
import { useBucketCreateMutation } from 'data/storage/bucket-create-mutation'
|
||||
import { useStore } from 'hooks'
|
||||
import { IS_PLATFORM } from 'lib/constants'
|
||||
|
||||
export interface CreateBucketModalProps {
|
||||
visible: boolean
|
||||
onClose: () => void
|
||||
}
|
||||
|
||||
const CreateBucketModal = ({ visible, onClose }: CreateBucketModalProps) => {
|
||||
const { ui } = useStore()
|
||||
const { ref } = useParams()
|
||||
const router = useRouter()
|
||||
|
||||
const { mutate: createBucket, isLoading: isCreating } = useBucketCreateMutation({
|
||||
onSuccess: (res) => {
|
||||
ui.setNotification({
|
||||
category: 'success',
|
||||
message: `Successfully created bucket ${res.name}`,
|
||||
})
|
||||
toast.success(`Successfully created bucket ${res.name}`)
|
||||
router.push(`/project/${ref}/storage/buckets/${res.name}`)
|
||||
onClose()
|
||||
},
|
||||
@@ -163,7 +159,7 @@ const CreateBucketModal = ({ visible, onClose }: CreateBucketModalProps) => {
|
||||
<IconChevronDown
|
||||
size={18}
|
||||
strokeWidth={2}
|
||||
className={clsx('text-foreground-light', showConfiguration && 'rotate-180')}
|
||||
className={cn('text-foreground-light', showConfiguration && 'rotate-180')}
|
||||
/>
|
||||
</div>
|
||||
</Collapsible.Trigger>
|
||||
|
||||
@@ -1,8 +1,24 @@
|
||||
import { useParams } from 'common'
|
||||
import { CLIENT_LIBRARIES } from 'common/constants'
|
||||
import { HelpCircle } from 'lucide-react'
|
||||
import Link from 'next/link'
|
||||
import { useRouter } from 'next/router'
|
||||
import { ChangeEvent, useEffect, useRef, useState } from 'react'
|
||||
import toast from 'react-hot-toast'
|
||||
|
||||
import { useParams } from 'common'
|
||||
import Divider from 'components/ui/Divider'
|
||||
import InformationBox from 'components/ui/InformationBox'
|
||||
import ShimmeringLoader from 'components/ui/ShimmeringLoader'
|
||||
import { getProjectAuthConfig } from 'data/auth/auth-config-query'
|
||||
import { useSendSupportTicketMutation } from 'data/feedback/support-ticket-send'
|
||||
import { useOrganizationsQuery } from 'data/organizations/organizations-query'
|
||||
import type { Project } from 'data/projects/project-detail-query'
|
||||
import { useProjectsQuery } from 'data/projects/projects-query'
|
||||
import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query'
|
||||
import { useFlag } from 'hooks'
|
||||
import useLatest from 'hooks/misc/useLatest'
|
||||
import { detectBrowser } from 'lib/helpers'
|
||||
import { useProfile } from 'lib/profile'
|
||||
import {
|
||||
AlertDescription_Shadcn_,
|
||||
AlertTitle_Shadcn_,
|
||||
@@ -19,22 +35,7 @@ import {
|
||||
Input,
|
||||
Listbox,
|
||||
} from 'ui'
|
||||
|
||||
import Divider from 'components/ui/Divider'
|
||||
import InformationBox from 'components/ui/InformationBox'
|
||||
import MultiSelect from 'ui-patterns/MultiSelect'
|
||||
import ShimmeringLoader from 'components/ui/ShimmeringLoader'
|
||||
import { getProjectAuthConfig } from 'data/auth/auth-config-query'
|
||||
import { useSendSupportTicketMutation } from 'data/feedback/support-ticket-send'
|
||||
import { useOrganizationsQuery } from 'data/organizations/organizations-query'
|
||||
import type { Project } from 'data/projects/project-detail-query'
|
||||
import { useProjectsQuery } from 'data/projects/projects-query'
|
||||
import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query'
|
||||
import { useFlag, useStore } from 'hooks'
|
||||
import useLatest from 'hooks/misc/useLatest'
|
||||
import { detectBrowser } from 'lib/helpers'
|
||||
import { useProfile } from 'lib/profile'
|
||||
import { HelpCircle } from 'lucide-react'
|
||||
import DisabledStateForFreeTier from './DisabledStateForFreeTier'
|
||||
import { CATEGORY_OPTIONS, SERVICE_OPTIONS, SEVERITY_OPTIONS } from './Support.constants'
|
||||
import { formatMessage, uploadAttachments } from './SupportForm.utils'
|
||||
@@ -47,7 +48,6 @@ export interface SupportFormProps {
|
||||
}
|
||||
|
||||
const SupportForm = ({ setSentCategory }: SupportFormProps) => {
|
||||
const { ui } = useStore()
|
||||
const { isReady } = useRouter()
|
||||
const { ref, slug, subject, category, message } = useParams()
|
||||
|
||||
@@ -77,15 +77,11 @@ const SupportForm = ({ setSentCategory }: SupportFormProps) => {
|
||||
|
||||
const { mutate: submitSupportTicket } = useSendSupportTicketMutation({
|
||||
onSuccess: (res, variables) => {
|
||||
ui.setNotification({ category: 'success', message: 'Support request sent. Thank you!' })
|
||||
toast.success('Support request sent. Thank you!')
|
||||
setSentCategory(variables.category)
|
||||
},
|
||||
onError: (error) => {
|
||||
ui.setNotification({
|
||||
error,
|
||||
category: 'error',
|
||||
message: `Failed to submit support ticket: ${error.message}`,
|
||||
})
|
||||
toast.error(`Failed to submit support ticket: ${error.message}`)
|
||||
setIsSubmitting(false)
|
||||
},
|
||||
})
|
||||
@@ -146,10 +142,7 @@ const SupportForm = ({ setSentCategory }: SupportFormProps) => {
|
||||
|
||||
setUploadedFiles(uploadedFiles.concat(itemsToBeUploaded))
|
||||
if (items.length + uploadedFiles.length > MAX_ATTACHMENTS) {
|
||||
ui.setNotification({
|
||||
category: 'info',
|
||||
message: `Only up to ${MAX_ATTACHMENTS} attachments are allowed`,
|
||||
})
|
||||
toast(`Only up to ${MAX_ATTACHMENTS} attachments are allowed`)
|
||||
}
|
||||
|
||||
event.target.value = ''
|
||||
|
||||
@@ -1,28 +1,28 @@
|
||||
import * as Tooltip from '@radix-ui/react-tooltip'
|
||||
import { PermissionAction } from '@supabase/shared-types/out/constants'
|
||||
import { useQueryClient } from '@tanstack/react-query'
|
||||
import { useParams } from 'common'
|
||||
import Link from 'next/link'
|
||||
import { useState } from 'react'
|
||||
import { Button, IconPauseCircle, Modal } from 'ui'
|
||||
import toast from 'react-hot-toast'
|
||||
|
||||
import ConfirmModal from 'ui-patterns/Dialogs/ConfirmDialog'
|
||||
import { useParams } from 'common'
|
||||
import { useFreeProjectLimitCheckQuery } from 'data/organizations/free-project-limit-check-query'
|
||||
import { useProjectRestoreMutation } from 'data/projects/project-restore-mutation'
|
||||
import { setProjectStatus } from 'data/projects/projects-query'
|
||||
import { useCheckPermissions, useSelectedOrganization, useStore } from 'hooks'
|
||||
import { PROJECT_STATUS } from 'lib/constants'
|
||||
import { useProjectContext } from './ProjectContext'
|
||||
import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query'
|
||||
import { useCheckPermissions, useSelectedOrganization } from 'hooks'
|
||||
import { PROJECT_STATUS } from 'lib/constants'
|
||||
import { Button, IconPauseCircle, Modal } from 'ui'
|
||||
import ConfirmModal from 'ui-patterns/Dialogs/ConfirmDialog'
|
||||
import { useProjectContext } from './ProjectContext'
|
||||
|
||||
export interface ProjectPausedStateProps {
|
||||
product?: string
|
||||
}
|
||||
|
||||
const ProjectPausedState = ({ product }: ProjectPausedStateProps) => {
|
||||
const queryClient = useQueryClient()
|
||||
const { ui } = useStore()
|
||||
const { ref } = useParams()
|
||||
const queryClient = useQueryClient()
|
||||
const selectedOrganization = useSelectedOrganization()
|
||||
const { project } = useProjectContext()
|
||||
const orgSlug = selectedOrganization?.slug
|
||||
@@ -42,7 +42,7 @@ const ProjectPausedState = ({ product }: ProjectPausedStateProps) => {
|
||||
const { mutate: restoreProject } = useProjectRestoreMutation({
|
||||
onSuccess: (res, variables) => {
|
||||
setProjectStatus(queryClient, variables.ref, PROJECT_STATUS.RESTORING)
|
||||
ui.setNotification({ category: 'success', message: 'Restoring project' })
|
||||
toast.success('Restoring project')
|
||||
},
|
||||
})
|
||||
|
||||
@@ -53,21 +53,14 @@ const ProjectPausedState = ({ product }: ProjectPausedStateProps) => {
|
||||
|
||||
const onSelectRestore = () => {
|
||||
if (!canResumeProject) {
|
||||
ui.setNotification({
|
||||
category: 'error',
|
||||
message: 'You do not have the required permissions to restore this project',
|
||||
})
|
||||
toast.error('You do not have the required permissions to restore this project')
|
||||
} else if (hasMembersExceedingFreeTierLimit) setShowFreeProjectLimitWarning(true)
|
||||
else setShowConfirmRestore(true)
|
||||
}
|
||||
|
||||
const onConfirmRestore = () => {
|
||||
if (!project) {
|
||||
return ui.setNotification({
|
||||
error: 'Project is required',
|
||||
category: 'error',
|
||||
message: 'Unable to restore: project is required',
|
||||
})
|
||||
return toast.error('Unable to restore: project is required')
|
||||
}
|
||||
restoreProject({ ref: project.ref })
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user