mirror of
https://github.com/supabase/supabase.git
synced 2026-10-18 23:59:08 +03:00
Support downloading storage objects in project paused state
This commit is contained in:
1 parent
40322b20b6
commit
42f8b95eb2
9 files changed
+380
-156
No files matched your search
+30
-64
@@ -1,8 +1,8 @@
|
||||
import Link from 'next/link'
|
||||
import { Button } from 'ui'
|
||||
import { Admonition } from 'ui-patterns/admonition'
|
||||
|
||||
import type { MemberWithFreeProjectLimit } from 'data/organizations/free-project-limit-check-query'
|
||||
import { Button } from 'ui'
|
||||
import { Admonition } from 'ui-patterns/admonition'
|
||||
|
||||
interface FreeProjectLimitWarningProps {
|
||||
membersExceededLimit: MemberWithFreeProjectLimit[]
|
||||
@@ -14,70 +14,36 @@ const FreeProjectLimitWarning = ({
|
||||
orgSlug,
|
||||
}: FreeProjectLimitWarningProps) => {
|
||||
return (
|
||||
<>
|
||||
<Admonition
|
||||
type={'default'}
|
||||
title={'The organization has members who have exceeded their free project limits'}
|
||||
description={
|
||||
<div className="space-y-3">
|
||||
<p className="text-sm leading-normal">
|
||||
The following members have reached their maximum limits for the number of active free
|
||||
plan projects within organizations where they are an administrator or owner:
|
||||
</p>
|
||||
<ul className="pl-5 list-disc">
|
||||
{membersExceededLimit.map((member, idx: number) => (
|
||||
<li key={`member-${idx}`}>
|
||||
{member.username || member.primary_email} (Limit: {member.free_project_limit} free
|
||||
projects)
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<p className="text-sm leading-normal">
|
||||
These members will need to either delete, pause, or upgrade one or more of these
|
||||
projects before you're able to create a free project within this organization.
|
||||
</p>
|
||||
<Admonition
|
||||
type={'default'}
|
||||
title={'The organization has members who have exceeded their free project limits'}
|
||||
description={
|
||||
<div className="space-y-3">
|
||||
<p className="text-sm leading-normal">
|
||||
The following members have reached their maximum limits for the number of active free
|
||||
plan projects within organizations where they are an administrator or owner:
|
||||
</p>
|
||||
<ul className="pl-5 list-disc">
|
||||
{membersExceededLimit.map((member, idx: number) => (
|
||||
<li key={`member-${idx}`}>
|
||||
{member.username || member.primary_email} (Limit: {member.free_project_limit} free
|
||||
projects)
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<p className="text-sm leading-normal">
|
||||
These members will need to either delete, pause, or upgrade one or more of these
|
||||
projects before you're able to create a free project within this organization.
|
||||
</p>
|
||||
|
||||
<div>
|
||||
<Button asChild type="secondary">
|
||||
<Link href={`/org/${orgSlug}/billing?panel=subscriptionPlan`}>Upgrade plan</Link>
|
||||
</Button>
|
||||
</div>
|
||||
<div>
|
||||
<Button asChild type="secondary">
|
||||
<Link href={`/org/${orgSlug}/billing?panel=subscriptionPlan`}>Upgrade plan</Link>
|
||||
</Button>
|
||||
</div>
|
||||
}
|
||||
></Admonition>
|
||||
{/* <InformationBox
|
||||
icon={<AlertCircle className="text-foreground" size="large" strokeWidth={1.5} />}
|
||||
defaultVisibility={true}
|
||||
hideCollapse
|
||||
title="The organization has members who have exceeded their free project limits"
|
||||
description={
|
||||
<div className="space-y-3">
|
||||
<p className="text-sm leading-normal">
|
||||
The following members have reached their maximum limits for the number of active free
|
||||
plan projects within organizations where they are an administrator or owner:
|
||||
</p>
|
||||
<ul className="pl-5 list-disc">
|
||||
{membersExceededLimit.map((member, idx: number) => (
|
||||
<li key={`member-${idx}`}>
|
||||
{member.username || member.primary_email} (Limit: {member.free_project_limit} free
|
||||
projects)
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<p className="text-sm leading-normal">
|
||||
These members will need to either delete, pause, or upgrade one or more of these
|
||||
projects before you're able to create a free project within this organization.
|
||||
</p>
|
||||
|
||||
<div>
|
||||
<Button asChild type="primary">
|
||||
<Link href={`/org/${orgSlug}/billing?panel=subscriptionPlan`}>Upgrade plan</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
/> */}
|
||||
</>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,144 @@
|
||||
import { toast } from 'sonner'
|
||||
import { ChevronDown, Download } from 'lucide-react'
|
||||
|
||||
import { useParams } from 'common'
|
||||
import { useProjectPauseStatusQuery } from 'data/projects/project-pause-status-query'
|
||||
import {
|
||||
Alert_Shadcn_,
|
||||
AlertDescription_Shadcn_,
|
||||
AlertTitle_Shadcn_,
|
||||
Button,
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuTrigger,
|
||||
WarningIcon,
|
||||
} from 'ui'
|
||||
import { useProjectContext } from '../ProjectContext'
|
||||
import { PROJECT_STATUS } from 'lib/constants'
|
||||
import { useFlag } from 'hooks/ui/useFlag'
|
||||
import { useBackupDownloadMutation } from 'data/database/backup-download-mutation'
|
||||
import { useStorageArchiveQuery } from 'data/storage/storage-archive-query'
|
||||
import { DropdownMenuItemTooltip } from 'components/ui/DropdownMenuItemTooltip'
|
||||
import { Database, Storage } from 'icons'
|
||||
|
||||
export const PauseDisabledState = () => {
|
||||
const { ref } = useParams()
|
||||
const { project } = useProjectContext()
|
||||
const enforceNinetyDayUnpauseExpiry = useFlag('enforceNinetyDayUnpauseExpiry')
|
||||
|
||||
const { data: pauseStatus } = useProjectPauseStatusQuery(
|
||||
{ ref },
|
||||
{
|
||||
enabled: project?.status === PROJECT_STATUS.INACTIVE && enforceNinetyDayUnpauseExpiry,
|
||||
}
|
||||
)
|
||||
const latestBackup = pauseStatus?.latest_downloadable_backup_id
|
||||
|
||||
const { data: storageArchive } = useStorageArchiveQuery({ projectRef: ref })
|
||||
const storageArchiveUrl = storageArchive?.fileUrl
|
||||
|
||||
const { mutate: downloadBackup } = useBackupDownloadMutation({
|
||||
onSuccess: (res) => {
|
||||
const { fileUrl } = res
|
||||
|
||||
// Trigger browser download by create,trigger and remove tempLink
|
||||
const tempLink = document.createElement('a')
|
||||
tempLink.href = fileUrl
|
||||
document.body.appendChild(tempLink)
|
||||
tempLink.click()
|
||||
document.body.removeChild(tempLink)
|
||||
},
|
||||
})
|
||||
|
||||
const onSelectDownloadBackup = () => {
|
||||
if (ref === undefined) return console.error('Project ref is required')
|
||||
if (!latestBackup) return toast.error('No backups available for download')
|
||||
|
||||
const toastId = toast.loading('Fetching database backup')
|
||||
|
||||
downloadBackup(
|
||||
{
|
||||
ref,
|
||||
backup: {
|
||||
id: latestBackup,
|
||||
// [Joshen] Just FYI these params aren't required for the download backup request
|
||||
// API types need to be updated
|
||||
project_id: -1,
|
||||
inserted_at: '',
|
||||
isPhysicalBackup: false,
|
||||
status: {},
|
||||
},
|
||||
},
|
||||
{
|
||||
onSuccess: () => {
|
||||
toast.success('Downloading database backup', { id: toastId })
|
||||
},
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
const onSelectDownloadStorageArchive = () => {
|
||||
if (!storageArchiveUrl) return toast.error('No storage archive available for download')
|
||||
toast.success('Downloading storage objects')
|
||||
// Trigger browser download by create,trigger and remove tempLink
|
||||
const tempLink = document.createElement('a')
|
||||
tempLink.href = storageArchiveUrl
|
||||
document.body.appendChild(tempLink)
|
||||
tempLink.click()
|
||||
document.body.removeChild(tempLink)
|
||||
}
|
||||
|
||||
return (
|
||||
<Alert_Shadcn_ variant="warning">
|
||||
<WarningIcon />
|
||||
<AlertTitle_Shadcn_>Project cannot be restored through the dashboard</AlertTitle_Shadcn_>
|
||||
<AlertDescription_Shadcn_>
|
||||
This project has been paused for over{' '}
|
||||
<span className="text-foreground">
|
||||
{pauseStatus?.max_days_till_restore_disabled ?? 90} days
|
||||
</span>{' '}
|
||||
and cannot be restored through the dashboard. However, your data remains intact and can be
|
||||
downloaded as a backup.
|
||||
</AlertDescription_Shadcn_>
|
||||
<AlertDescription_Shadcn_ className="flex items-center gap-x-2 mt-3">
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button type="default" icon={<Download />} iconRight={<ChevronDown />}>
|
||||
Download backup
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="w-56" align="start">
|
||||
<DropdownMenuItemTooltip
|
||||
className="gap-x-2"
|
||||
disabled={!latestBackup}
|
||||
onClick={() => onSelectDownloadBackup()}
|
||||
tooltip={{
|
||||
content: {
|
||||
side: 'right',
|
||||
text: 'No backups available, please reach out via support for assistance',
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Database size={16} />
|
||||
Download database backup
|
||||
</DropdownMenuItemTooltip>
|
||||
<DropdownMenuItemTooltip
|
||||
disabled={!storageArchiveUrl}
|
||||
className="gap-x-2"
|
||||
onClick={() => onSelectDownloadStorageArchive()}
|
||||
tooltip={{
|
||||
content: {
|
||||
side: 'right',
|
||||
text: 'No storage archive available for download',
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Storage size={16} />
|
||||
Download storage objects
|
||||
</DropdownMenuItemTooltip>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</AlertDescription_Shadcn_>
|
||||
</Alert_Shadcn_>
|
||||
)
|
||||
}
|
||||
+8
-87
@@ -1,7 +1,7 @@
|
||||
import { PermissionAction } from '@supabase/shared-types/out/constants'
|
||||
import { useQueryClient } from '@tanstack/react-query'
|
||||
import dayjs from 'dayjs'
|
||||
import { Download, PauseCircle } from 'lucide-react'
|
||||
import { PauseCircle } from 'lucide-react'
|
||||
import Link from 'next/link'
|
||||
import { useState } from 'react'
|
||||
import { toast } from 'sonner'
|
||||
@@ -9,7 +9,6 @@ import { toast } from 'sonner'
|
||||
import { useParams } from 'common'
|
||||
import AlertError from 'components/ui/AlertError'
|
||||
import { ButtonTooltip } from 'components/ui/ButtonTooltip'
|
||||
import { useBackupDownloadMutation } from 'data/database/backup-download-mutation'
|
||||
import { useFreeProjectLimitCheckQuery } from 'data/organizations/free-project-limit-check-query'
|
||||
import { useProjectPauseStatusQuery } from 'data/projects/project-pause-status-query'
|
||||
import { useProjectRestoreMutation } from 'data/projects/project-restore-mutation'
|
||||
@@ -19,27 +18,18 @@ import { useCheckPermissions } from 'hooks/misc/useCheckPermissions'
|
||||
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
|
||||
import { useFlag } from 'hooks/ui/useFlag'
|
||||
import { PROJECT_STATUS } from 'lib/constants'
|
||||
import {
|
||||
AlertDescription_Shadcn_,
|
||||
AlertTitle_Shadcn_,
|
||||
Alert_Shadcn_,
|
||||
Button,
|
||||
Modal,
|
||||
TooltipContent_Shadcn_,
|
||||
TooltipTrigger_Shadcn_,
|
||||
Tooltip_Shadcn_,
|
||||
WarningIcon,
|
||||
} from 'ui'
|
||||
import { AlertDescription_Shadcn_, AlertTitle_Shadcn_, Alert_Shadcn_, Button, Modal } from 'ui'
|
||||
import { GenericSkeletonLoader } from 'ui-patterns'
|
||||
import ConfirmModal from 'ui-patterns/Dialogs/ConfirmDialog'
|
||||
import { useProjectContext } from './ProjectContext'
|
||||
import { RestorePaidPlanProjectNotice } from './RestorePaidPlanProjectNotice'
|
||||
import { useProjectContext } from '../ProjectContext'
|
||||
import { RestorePaidPlanProjectNotice } from '../RestorePaidPlanProjectNotice'
|
||||
import { PauseDisabledState } from './PauseDisabledState'
|
||||
|
||||
export interface ProjectPausedStateProps {
|
||||
product?: string
|
||||
}
|
||||
|
||||
const ProjectPausedState = ({ product }: ProjectPausedStateProps) => {
|
||||
export const ProjectPausedState = ({ product }: ProjectPausedStateProps) => {
|
||||
const { ref } = useParams()
|
||||
const queryClient = useQueryClient()
|
||||
const { project } = useProjectContext()
|
||||
@@ -67,8 +57,7 @@ const ProjectPausedState = ({ product }: ProjectPausedStateProps) => {
|
||||
0
|
||||
|
||||
const isFreePlan = subscription?.plan?.id === 'free'
|
||||
const isRestoreDisabled = enforceNinetyDayUnpauseExpiry && isSuccess && !pauseStatus.can_restore
|
||||
const latestBackup = pauseStatus?.latest_downloadable_backup_id
|
||||
const isRestoreDisabled = true // enforceNinetyDayUnpauseExpiry && isSuccess && !pauseStatus.can_restore
|
||||
|
||||
const { data: membersExceededLimit } = useFreeProjectLimitCheckQuery(
|
||||
{ slug: orgSlug },
|
||||
@@ -86,19 +75,6 @@ const ProjectPausedState = ({ product }: ProjectPausedStateProps) => {
|
||||
},
|
||||
})
|
||||
|
||||
const { mutate: downloadBackup, isLoading: isDownloading } = useBackupDownloadMutation({
|
||||
onSuccess: (res) => {
|
||||
const { fileUrl } = res
|
||||
|
||||
// Trigger browser download by create,trigger and remove tempLink
|
||||
const tempLink = document.createElement('a')
|
||||
tempLink.href = fileUrl
|
||||
document.body.appendChild(tempLink)
|
||||
tempLink.click()
|
||||
document.body.removeChild(tempLink)
|
||||
},
|
||||
})
|
||||
|
||||
const canResumeProject = useCheckPermissions(
|
||||
PermissionAction.INFRA_EXECUTE,
|
||||
'queue_jobs.projects.initialize_or_resume'
|
||||
@@ -118,24 +94,6 @@ const ProjectPausedState = ({ product }: ProjectPausedStateProps) => {
|
||||
restoreProject({ ref: project.ref })
|
||||
}
|
||||
|
||||
const onSelectDownloadBackup = () => {
|
||||
if (ref === undefined) return console.error('Project ref is required')
|
||||
if (!latestBackup) return toast.error('No backups available for download')
|
||||
|
||||
downloadBackup({
|
||||
ref,
|
||||
backup: {
|
||||
id: latestBackup,
|
||||
// [Joshen] Just FYI these params aren't required for the download backup request
|
||||
// API types need to be updated
|
||||
project_id: -1,
|
||||
inserted_at: '',
|
||||
isPhysicalBackup: false,
|
||||
status: {},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="space-y-4">
|
||||
@@ -177,42 +135,7 @@ const ProjectPausedState = ({ product }: ProjectPausedStateProps) => {
|
||||
{isSuccess && (
|
||||
<>
|
||||
{isRestoreDisabled ? (
|
||||
<Alert_Shadcn_ variant="warning">
|
||||
<WarningIcon />
|
||||
<AlertTitle_Shadcn_>
|
||||
Project cannot be restored through the dashboard
|
||||
</AlertTitle_Shadcn_>
|
||||
<AlertDescription_Shadcn_>
|
||||
This project has been paused for over{' '}
|
||||
<span className="text-foreground">
|
||||
{pauseStatus?.max_days_till_restore_disabled ?? 90} days
|
||||
</span>{' '}
|
||||
and cannot be restored through the dashboard. However, your data
|
||||
remains intact and can be downloaded as a backup.
|
||||
</AlertDescription_Shadcn_>
|
||||
<AlertDescription_Shadcn_ className="flex items-center gap-x-2 mt-3">
|
||||
<Tooltip_Shadcn_>
|
||||
<TooltipTrigger_Shadcn_ asChild>
|
||||
<Button
|
||||
type="default"
|
||||
icon={<Download />}
|
||||
loading={isDownloading}
|
||||
disabled={!latestBackup}
|
||||
className="pointer-events-auto"
|
||||
onClick={() => onSelectDownloadBackup()}
|
||||
>
|
||||
Download backup
|
||||
</Button>
|
||||
</TooltipTrigger_Shadcn_>
|
||||
{!latestBackup && (
|
||||
<TooltipContent_Shadcn_ side="bottom">
|
||||
No backups available, please reach out via support for
|
||||
assistance
|
||||
</TooltipContent_Shadcn_>
|
||||
)}
|
||||
</Tooltip_Shadcn_>
|
||||
</AlertDescription_Shadcn_>
|
||||
</Alert_Shadcn_>
|
||||
<PauseDisabledState />
|
||||
) : isFreePlan ? (
|
||||
<>
|
||||
<p className="text-sm text-foreground-light text-center">
|
||||
@@ -337,5 +260,3 @@ const ProjectPausedState = ({ product }: ProjectPausedStateProps) => {
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default ProjectPausedState
|
||||
@@ -25,7 +25,7 @@ import PauseFailedState from './PauseFailedState'
|
||||
import PausingState from './PausingState'
|
||||
import ProductMenuBar from './ProductMenuBar'
|
||||
import { ProjectContextProvider } from './ProjectContext'
|
||||
import ProjectPausedState from './ProjectPausedState'
|
||||
import { ProjectPausedState } from './PausedState/ProjectPausedState'
|
||||
import RestartingState from './RestartingState'
|
||||
import RestoreFailedState from './RestoreFailedState'
|
||||
import RestoringState from './RestoringState'
|
||||
|
||||
@@ -4,6 +4,8 @@ import { components } from 'api-types'
|
||||
import { get, handleError } from 'data/fetchers'
|
||||
import type { ResponseError } from 'types'
|
||||
import { configKeys } from './keys'
|
||||
import { useSelectedProject } from 'hooks/misc/useSelectedProject'
|
||||
import { PROJECT_STATUS } from 'lib/constants'
|
||||
|
||||
export type ProjectApiVariables = {
|
||||
projectRef?: string
|
||||
@@ -17,6 +19,7 @@ export type ProjectApiResponse = {
|
||||
|
||||
export async function getProjectApi({ projectRef }: ProjectApiVariables, signal?: AbortSignal) {
|
||||
if (!projectRef) throw new Error('projectRef is required')
|
||||
console.log('SSS')
|
||||
|
||||
const { data, error } = await get('/platform/props/project/{ref}/api', {
|
||||
params: { path: { ref: projectRef } },
|
||||
@@ -33,12 +36,16 @@ export type ProjectApiError = ResponseError
|
||||
export const useProjectApiQuery = <TData = ProjectApiData>(
|
||||
{ projectRef }: ProjectApiVariables,
|
||||
{ enabled = true, ...options }: UseQueryOptions<ProjectApiData, ProjectApiError, TData> = {}
|
||||
) =>
|
||||
useQuery<ProjectApiData, ProjectApiError, TData>(
|
||||
) => {
|
||||
const project = useSelectedProject()
|
||||
return useQuery<ProjectApiData, ProjectApiError, TData>(
|
||||
configKeys.api(projectRef),
|
||||
({ signal }) => getProjectApi({ projectRef }, signal),
|
||||
{
|
||||
enabled: enabled && typeof projectRef !== 'undefined',
|
||||
enabled:
|
||||
enabled &&
|
||||
typeof projectRef !== 'undefined' &&
|
||||
project?.status === PROJECT_STATUS.ACTIVE_HEALTHY,
|
||||
refetchInterval(data, query) {
|
||||
if (!data) {
|
||||
return false
|
||||
@@ -54,3 +61,4 @@ export const useProjectApiQuery = <TData = ProjectApiData>(
|
||||
...options,
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
export const storageKeys = {
|
||||
buckets: (projectRef: string | undefined) => ['projects', projectRef, 'buckets'] as const,
|
||||
archive: (projectRef: string | undefined) => ['projects', projectRef, 'archive'] as const,
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
import { UseQueryOptions, useQuery } from '@tanstack/react-query'
|
||||
|
||||
import { get, handleError } from 'data/fetchers'
|
||||
import { ResponseError } from 'types'
|
||||
import { storageKeys } from './keys'
|
||||
|
||||
type StorageArchiveVariables = { projectRef?: string }
|
||||
|
||||
async function fetchStorageArchive({ projectRef }: StorageArchiveVariables, signal?: AbortSignal) {
|
||||
if (!projectRef) throw new Error('projectRef is required')
|
||||
|
||||
const { data, error } = await get('/platform/storage/{ref}/archive', {
|
||||
params: { path: { ref: projectRef } },
|
||||
signal,
|
||||
})
|
||||
if (error) {
|
||||
if ((error as ResponseError)?.message?.includes('Storage archive not found')) {
|
||||
return { fileUrl: undefined }
|
||||
} else {
|
||||
handleError(error)
|
||||
}
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
export type StorageArchiveData = Awaited<ReturnType<typeof fetchStorageArchive>>
|
||||
|
||||
export const useStorageArchiveQuery = <TData = StorageArchiveData>(
|
||||
{ projectRef }: StorageArchiveVariables,
|
||||
{ enabled = true, ...options }: UseQueryOptions<StorageArchiveData, ResponseError, TData> = {}
|
||||
) =>
|
||||
useQuery<StorageArchiveData, ResponseError, TData>(
|
||||
storageKeys.archive(projectRef),
|
||||
({ signal }) => fetchStorageArchive({ projectRef }, signal),
|
||||
{ enabled: enabled && typeof projectRef !== 'undefined', ...options }
|
||||
)
|
||||
@@ -8,7 +8,7 @@ import ProjectUsageSection from 'components/interfaces/Home/ProjectUsageSection'
|
||||
import { SecurityStatus } from 'components/interfaces/Home/SecurityStatus'
|
||||
import ServiceStatus from 'components/interfaces/Home/ServiceStatus'
|
||||
import { ProjectLayoutWithAuth } from 'components/layouts/ProjectLayout/ProjectLayout'
|
||||
import ProjectPausedState from 'components/layouts/ProjectLayout/ProjectPausedState'
|
||||
import { ProjectPausedState } from 'components/layouts/ProjectLayout/PausedState/ProjectPausedState'
|
||||
import { ComputeBadgeWrapper } from 'components/ui/ComputeBadgeWrapper'
|
||||
import ProjectUpgradeFailedBanner from 'components/ui/ProjectUpgradeFailedBanner'
|
||||
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
|
||||
|
||||
Vendored
+148
@@ -989,6 +989,12 @@ export interface paths {
|
||||
/** Get infrastructure status */
|
||||
get: operations['StatusController_getStatus']
|
||||
}
|
||||
'/platform/storage/{ref}/archive': {
|
||||
/** Gets project storage archive */
|
||||
get: operations['StorageArchiveController_getArchive']
|
||||
/** Creates project storage archive */
|
||||
post: operations['StorageArchiveController_createArchive']
|
||||
}
|
||||
'/platform/storage/{ref}/buckets': {
|
||||
/** Gets list of buckets */
|
||||
get: operations['StorageBucketsController_getBuckets']
|
||||
@@ -1794,6 +1800,12 @@ export interface paths {
|
||||
/** Get infrastructure status */
|
||||
get: operations['StatusController_getStatus']
|
||||
}
|
||||
'/v0/storage/{ref}/archive': {
|
||||
/** Gets project storage archive */
|
||||
get: operations['StorageArchiveController_getArchive']
|
||||
/** Creates project storage archive */
|
||||
post: operations['StorageArchiveController_createArchive']
|
||||
}
|
||||
'/v0/storage/{ref}/buckets': {
|
||||
/** Gets list of buckets */
|
||||
get: operations['StorageBucketsController_getBuckets']
|
||||
@@ -1919,6 +1931,14 @@ export interface paths {
|
||||
'/v1/projects/{ref}/api-keys': {
|
||||
/** Get project api keys */
|
||||
get: operations['v1-get-project-api-keys']
|
||||
/** [Alpha] Creates a new API key for the project */
|
||||
post: operations['ApiKeysController_createApiKey']
|
||||
}
|
||||
'/v1/projects/{ref}/api-keys/{id}': {
|
||||
/** [Alpha] Deletes an API key for the project */
|
||||
delete: operations['ApiKeysController_deleteApiKey']
|
||||
/** [Alpha] Updates an API key for the project */
|
||||
patch: operations['ApiKeysController_updateApiKey']
|
||||
}
|
||||
'/v1/projects/{ref}/branches': {
|
||||
/**
|
||||
@@ -2242,7 +2262,18 @@ export interface components {
|
||||
}
|
||||
ApiKeyResponse: {
|
||||
api_key: string
|
||||
description?: string | null
|
||||
hash?: string | null
|
||||
id?: string | null
|
||||
inserted_at?: string | null
|
||||
name: string
|
||||
prefix?: string | null
|
||||
secret_jwt_template?: components['schemas']['ApiKeySecretJWTTemplate'] | null
|
||||
type?: unknown
|
||||
updated_at?: string | null
|
||||
}
|
||||
ApiKeySecretJWTTemplate: {
|
||||
role: string
|
||||
}
|
||||
ApiResponse: {
|
||||
autoApiService: components['schemas']['AutoApiService']
|
||||
@@ -2622,6 +2653,12 @@ export interface components {
|
||||
token: string
|
||||
token_alias: string
|
||||
}
|
||||
CreateApiKeyBody: {
|
||||
description?: string | null
|
||||
secret_jwt_template?: components['schemas']['ApiKeySecretJWTTemplate'] | null
|
||||
/** @enum {string} */
|
||||
type: 'publishable' | 'secret'
|
||||
}
|
||||
CreateAwsPartnerOrganizationBody: {
|
||||
name: string
|
||||
partner_billing: components['schemas']['AwsPartnerBillingBody']
|
||||
@@ -3296,6 +3333,9 @@ export interface components {
|
||||
verify_jwt?: boolean
|
||||
version: number
|
||||
}
|
||||
GetArchiveResponse: {
|
||||
fileUrl: string
|
||||
}
|
||||
GetContentCountResponse: {
|
||||
count: number
|
||||
}
|
||||
@@ -5496,6 +5536,10 @@ export interface components {
|
||||
addon_type: components['schemas']['ProjectAddonType']
|
||||
addon_variant: components['schemas']['AddonVariantId']
|
||||
}
|
||||
UpdateApiKeyBody: {
|
||||
description?: string | null
|
||||
secret_jwt_template?: components['schemas']['ApiKeySecretJWTTemplate'] | null
|
||||
}
|
||||
UpdateAuthConfigBody: {
|
||||
api_max_request_duration?: number
|
||||
db_max_pool_size?: number
|
||||
@@ -12450,6 +12494,9 @@ export interface operations {
|
||||
201: {
|
||||
content: never
|
||||
}
|
||||
403: {
|
||||
content: never
|
||||
}
|
||||
/** @description Failed to pause the project */
|
||||
500: {
|
||||
content: never
|
||||
@@ -12558,6 +12605,9 @@ export interface operations {
|
||||
'application/json': components['schemas']['RestoreCancellation']
|
||||
}
|
||||
}
|
||||
403: {
|
||||
content: never
|
||||
}
|
||||
/** @description Failed to cancel project restoration */
|
||||
500: {
|
||||
content: never
|
||||
@@ -12816,6 +12866,44 @@ export interface operations {
|
||||
}
|
||||
}
|
||||
}
|
||||
/** Gets project storage archive */
|
||||
StorageArchiveController_getArchive: {
|
||||
parameters: {
|
||||
path: {
|
||||
/** @description Project ref */
|
||||
ref: string
|
||||
}
|
||||
}
|
||||
responses: {
|
||||
200: {
|
||||
content: {
|
||||
'application/json': components['schemas']['GetArchiveResponse']
|
||||
}
|
||||
}
|
||||
/** @description Failed to get project storage archive */
|
||||
500: {
|
||||
content: never
|
||||
}
|
||||
}
|
||||
}
|
||||
/** Creates project storage archive */
|
||||
StorageArchiveController_createArchive: {
|
||||
parameters: {
|
||||
path: {
|
||||
/** @description Project ref */
|
||||
ref: string
|
||||
}
|
||||
}
|
||||
responses: {
|
||||
201: {
|
||||
content: never
|
||||
}
|
||||
/** @description Failed to create project storage archive */
|
||||
500: {
|
||||
content: never
|
||||
}
|
||||
}
|
||||
}
|
||||
/** Gets list of buckets */
|
||||
StorageBucketsController_getBuckets: {
|
||||
parameters: {
|
||||
@@ -14531,11 +14619,71 @@ export interface operations {
|
||||
'application/json': components['schemas']['ApiKeyResponse'][]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/** [Alpha] Creates a new API key for the project */
|
||||
ApiKeysController_createApiKey: {
|
||||
parameters: {
|
||||
path: {
|
||||
/** @description Project ref */
|
||||
ref: string
|
||||
}
|
||||
}
|
||||
requestBody: {
|
||||
content: {
|
||||
'application/json': components['schemas']['CreateApiKeyBody']
|
||||
}
|
||||
}
|
||||
responses: {
|
||||
201: {
|
||||
content: {
|
||||
'application/json': components['schemas']['ApiKeyResponse']
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/** [Alpha] Deletes an API key for the project */
|
||||
ApiKeysController_deleteApiKey: {
|
||||
parameters: {
|
||||
path: {
|
||||
/** @description Project ref */
|
||||
ref: string
|
||||
id: string
|
||||
}
|
||||
}
|
||||
responses: {
|
||||
200: {
|
||||
content: {
|
||||
'application/json': components['schemas']['ApiKeyResponse']
|
||||
}
|
||||
}
|
||||
403: {
|
||||
content: never
|
||||
}
|
||||
}
|
||||
}
|
||||
/** [Alpha] Updates an API key for the project */
|
||||
ApiKeysController_updateApiKey: {
|
||||
parameters: {
|
||||
path: {
|
||||
/** @description Project ref */
|
||||
ref: string
|
||||
id: string
|
||||
}
|
||||
}
|
||||
requestBody: {
|
||||
content: {
|
||||
'application/json': components['schemas']['UpdateApiKeyBody']
|
||||
}
|
||||
}
|
||||
responses: {
|
||||
200: {
|
||||
content: {
|
||||
'application/json': components['schemas']['ApiKeyResponse']
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* List all database branches
|
||||
* @description Returns all database branches of the specified project.
|
||||
|
||||
Reference in new issue
Block a user