mirror of
https://github.com/supabase/supabase.git
synced 2026-09-07 02:20:52 +08:00
How to test: 1. Have multiple free orgs 2. Open the "create new project" page in those orgs (no need to create a project), notice the `/members/reached-free-project-limit'` API call 3. Delete any project in any of the orgs you have 4. Go to any of orgs and open the "create new project" page, the request should be sent again (it was purged from the cache) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Improved project deletion behavior so free project limit checks are refreshed across all organizations, reducing the chance of stale availability data. * Continued to refresh the deleted project’s details and, when applicable, the project list and organization details after deletion. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
75 lines
2.4 KiB
TypeScript
75 lines
2.4 KiB
TypeScript
import { useMutation, useQueryClient } from '@tanstack/react-query'
|
|
import { toast } from 'sonner'
|
|
|
|
import { projectKeys } from './keys'
|
|
import { useInvalidateProjectsInfiniteQuery } from './org-projects-infinite-query'
|
|
import { del, handleError } from '@/data/fetchers'
|
|
import { organizationKeys } from '@/data/organizations/keys'
|
|
import type { ResponseError, UseCustomMutationOptions } from '@/types'
|
|
|
|
export type ProjectDeleteVariables = {
|
|
projectRef: string
|
|
organizationSlug?: string
|
|
}
|
|
|
|
export async function deleteProject({ projectRef }: ProjectDeleteVariables) {
|
|
const { data, error } = await del('/platform/projects/{ref}', {
|
|
params: { path: { ref: projectRef } },
|
|
})
|
|
|
|
if (error) handleError(error)
|
|
return data
|
|
}
|
|
|
|
type ProjectDeleteData = Awaited<ReturnType<typeof deleteProject>>
|
|
|
|
export const useProjectDeleteMutation = ({
|
|
onSuccess,
|
|
onError,
|
|
...options
|
|
}: Omit<
|
|
UseCustomMutationOptions<ProjectDeleteData, ResponseError, ProjectDeleteVariables>,
|
|
'mutationFn'
|
|
> = {}) => {
|
|
const queryClient = useQueryClient()
|
|
const { invalidateProjectsQuery } = useInvalidateProjectsInfiniteQuery()
|
|
|
|
return useMutation<ProjectDeleteData, ResponseError, ProjectDeleteVariables>({
|
|
mutationFn: (vars) => deleteProject(vars),
|
|
async onSuccess(data, variables, context) {
|
|
// Free project limits are shared across all of a user's orgs, so clear the cached
|
|
// check for every org, not just the one the deleted project belonged to.
|
|
const freeProjectLimitCheckQueries = queryClient
|
|
.getQueryCache()
|
|
.findAll({ queryKey: ['organizations'] })
|
|
.filter((query) => query.queryKey[2] === 'free-project-limit-check')
|
|
|
|
await Promise.all([
|
|
queryClient.invalidateQueries({ queryKey: projectKeys.detail(data.ref) }),
|
|
...freeProjectLimitCheckQueries.map((query) =>
|
|
queryClient.invalidateQueries({ queryKey: query.queryKey })
|
|
),
|
|
])
|
|
|
|
if (variables.organizationSlug) {
|
|
await Promise.all([
|
|
invalidateProjectsQuery(),
|
|
queryClient.invalidateQueries({
|
|
queryKey: organizationKeys.detail(variables.organizationSlug),
|
|
}),
|
|
])
|
|
}
|
|
|
|
await onSuccess?.(data, variables, context)
|
|
},
|
|
async onError(data, variables, context) {
|
|
if (onError === undefined) {
|
|
toast.error(`Failed to delete project: ${data.message}`)
|
|
} else {
|
|
onError(data, variables, context)
|
|
}
|
|
},
|
|
...options,
|
|
})
|
|
}
|