import { PermissionAction } from '@supabase/shared-types/out/constants' import { Loader, Shield, Users, Wrench } from 'lucide-react' import { useEffect, useState } from 'react' import { toast } from 'sonner' import { ButtonTooltip } from 'components/ui/ButtonTooltip' import { DocsButton } from 'components/ui/DocsButton' import { useOrganizationsQuery } from 'data/organizations/organizations-query' import { useProjectTransferMutation } from 'data/projects/project-transfer-mutation' import { useProjectTransferPreviewQuery } from 'data/projects/project-transfer-preview-query' import { useCheckPermissions } from 'hooks/misc/useCheckPermissions' import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject' import { useFlag } from 'hooks/ui/useFlag' import { Button, InfoIcon, Listbox, Loading, Modal, WarningIcon } from 'ui' import { Admonition } from 'ui-patterns' const TransferProjectButton = () => { const { data: project } = useSelectedProjectQuery() const projectRef = project?.ref const projectOrgId = project?.organization_id const [isOpen, setIsOpen] = useState(false) const { data: allOrganizations } = useOrganizationsQuery({ enabled: isOpen }) const disableProjectTransfer = useFlag('disableProjectTransfer') const organizations = (allOrganizations || []).filter((it) => it.id !== projectOrgId) const [selectedOrg, setSelectedOrg] = useState() const { mutate: transferProject, error: transferError, isLoading: isTransferring, } = useProjectTransferMutation({ onSuccess: () => { toast.success(`Successfully transferred project ${project?.name}.`) setIsOpen(false) }, }) const { data: transferPreviewData, error: transferPreviewError, isLoading: transferPreviewIsLoading, remove, } = useProjectTransferPreviewQuery( { projectRef, targetOrganizationSlug: selectedOrg }, { enabled: !isTransferring && isOpen } ) useEffect(() => { if (isOpen) { // reset state setSelectedOrg(undefined) } else { // Invalidate cache remove() } }, [isOpen]) const canTransferProject = useCheckPermissions(PermissionAction.UPDATE, 'organizations') const toggle = () => { setIsOpen(!isOpen) } async function handleTransferProject() { if (project === undefined) return if (selectedOrg === undefined) return transferProject({ projectRef, targetOrganizationSlug: selectedOrg }) } return ( <> Transfer project toggle()} visible={isOpen} loading={isTransferring} size={'xlarge'} header={`Transfer project ${project?.name}`} customFooter={
} >

To transfer projects, the owner must be a member of both the source and target organizations. Consider the following before transferring your project:

{organizations && (
{organizations.length === 0 ? (
You do not have any organizations you can transfer your project to.
) : ( setSelectedOrg(slug)} placeholder="Select Organization" > Select Organization {organizations.map((x: any) => ( } > {x.name} ))} )}
)}
{selectedOrg !== undefined && (
{transferPreviewData && transferPreviewData.errors.length > 0 && (
{transferPreviewData.errors.map((error) => (

{error.message}

))}
{transferPreviewData.members_exceeding_free_project_limit.length > 0 && (

These members have reached their maximum limits for the number of active Free plan projects within organizations where they are an administrator or owner:

    {(transferPreviewData.members_exceeding_free_project_limit || []).map( (member, idx: number) => (
  • {member.name} (Limit: {member.limit} free projects)
  • ) )}

These members will need to either delete, pause, or upgrade one or more of their projects before you can transfer this project.

)}
)} {transferPreviewData && (transferPreviewData.warnings.length > 0 || transferPreviewData.info.length > 0) && (
{transferPreviewData.warnings.map((warning) => (

{warning.message}

))} {transferPreviewData.info.map((info) => (

{info.message}

))}
)} {transferPreviewError && !transferError && (

{transferPreviewError.message}

} /> )} {transferError && (

{transferError.message}

} /> )}
)}
) } export default TransferProjectButton