DiskSizeConfiguration.tsx225 lines · main
1import { PermissionAction } from '@supabase/shared-types/out/constants'
2import { useParams } from 'common'
3import { ExternalLink, Info } from 'lucide-react'
4import Link from 'next/link'
5import { SetStateAction } from 'react'
6import { toast } from 'sonner'
7import { Alert, AlertDescription, AlertTitle, Button, InfoIcon } from 'ui'
8import {
9 PageSection,
10 PageSectionContent,
11 PageSectionMeta,
12 PageSectionSummary,
13 PageSectionTitle,
14} from 'ui-patterns'
15
16import { Markdown } from '@/components/interfaces/Markdown'
17import DiskSizeConfigurationModal from '@/components/interfaces/Settings/Database/DiskSizeConfigurationModal'
18import { ButtonTooltip } from '@/components/ui/ButtonTooltip'
19import { DocsButton } from '@/components/ui/DocsButton'
20import Panel from '@/components/ui/Panel'
21import { useProjectDiskResizeMutation } from '@/data/config/project-disk-resize-mutation'
22import { useDatabaseSizeQuery } from '@/data/database/database-size-query'
23import { useCheckEntitlements } from '@/hooks/misc/useCheckEntitlements'
24import { useAsyncCheckPermissions } from '@/hooks/misc/useCheckPermissions'
25import { useIsFeatureEnabled } from '@/hooks/misc/useIsFeatureEnabled'
26import { useSelectedOrganizationQuery } from '@/hooks/misc/useSelectedOrganization'
27import {
28 useIsAwsNimbusCloudProvider,
29 useSelectedProjectQuery,
30} from '@/hooks/misc/useSelectedProject'
31import { useUrlState } from '@/hooks/ui/useUrlState'
32import { DOCS_URL } from '@/lib/constants'
33import { formatBytes } from '@/lib/helpers'
34
35export interface DiskSizeConfigurationProps {
36 disabled?: boolean
37}
38
39export const DiskSizeConfiguration = ({ disabled = false }: DiskSizeConfigurationProps) => {
40 const { ref: projectRef } = useParams()
41 const { data: project } = useSelectedProjectQuery()
42 const { data: organization } = useSelectedOrganizationQuery()
43
44 const isAwsNimbus = useIsAwsNimbusCloudProvider()
45 const { reportsAll } = useIsFeatureEnabled(['reports:all'])
46
47 const [{ show_increase_disk_size_modal }, setUrlParams] = useUrlState()
48 const showIncreaseDiskSizeModal = show_increase_disk_size_modal === 'true'
49 const setShowIncreaseDiskSizeModal = (value: SetStateAction<boolean>) => {
50 const show = typeof value === 'function' ? value(showIncreaseDiskSizeModal) : value
51 setUrlParams({ show_increase_disk_size_modal: show ? 'true' : undefined })
52 }
53
54 const { can: canUpdateDiskSizeConfig } = useAsyncCheckPermissions(
55 PermissionAction.UPDATE,
56 'projects',
57 {
58 resource: {
59 project_id: project?.id,
60 },
61 }
62 )
63
64 const { isPending: isUpdatingDiskSize } = useProjectDiskResizeMutation({
65 onSuccess: (_, variables) => {
66 toast.success(`Successfully updated disk size to ${variables.volumeSize} GB`)
67 setShowIncreaseDiskSizeModal(false)
68 },
69 })
70
71 const { hasAccess: hasAccessToDiskSizeConfig } = useCheckEntitlements(
72 'instances.disk_modifications'
73 )
74
75 const currentDiskSize = project?.volumeSizeGb ?? 0
76
77 const { data } = useDatabaseSizeQuery({
78 projectRef: project?.ref,
79 connectionString: project?.connectionString,
80 })
81 const databaseSizeBytesUsed = data ?? 0
82
83 return (
84 <>
85 <PageSection id="disk-management">
86 <PageSectionMeta>
87 <PageSectionSummary>
88 <PageSectionTitle>Disk Management</PageSectionTitle>
89 </PageSectionSummary>
90 <DocsButton href={`${DOCS_URL}/guides/platform/database-size#disk-management`} />
91 </PageSectionMeta>
92 <PageSectionContent>
93 {organization?.usage_billing_enabled === true ? (
94 <div className="flex flex-col gap-3">
95 <Panel className="m-0!">
96 <Panel.Content>
97 <div>
98 <div>
99 {currentDiskSize && (
100 <span className="text-foreground-light flex gap-2 items-baseline">
101 <h4 className="text-foreground">Current Disk Storage</h4>
102 </span>
103 )}
104 <div className="grid grid-cols-2 items-center">
105 <p className="text-sm text-lighter max-w-lg">
106 Briven employs auto-scaling storage and allows for manual disk size
107 adjustments when necessary
108 </p>
109 {!isAwsNimbus && (
110 <ButtonTooltip
111 type="default"
112 className="w-min ml-auto"
113 disabled={!canUpdateDiskSizeConfig || disabled}
114 onClick={() => setShowIncreaseDiskSizeModal(true)}
115 tooltip={{
116 content: {
117 side: 'bottom',
118 text: !canUpdateDiskSizeConfig
119 ? 'You need additional permissions to increase the disk size'
120 : undefined,
121 },
122 }}
123 >
124 Increase disk size
125 </ButtonTooltip>
126 )}
127 </div>
128
129 <div className="grid grid-cols-12 gap-2 mt-12 items-start">
130 <div className="col-span-4 grid grid-cols-2 gap-x-12 gap-y-4 items-start">
131 <div className="grid gap-2 col-span-1">
132 <h5>Space used</h5>
133 <span className="text-lg">
134 {formatBytes(databaseSizeBytesUsed, 2, 'GB')}
135 </span>
136 </div>
137 <div className="grid gap-2 col-span-1">
138 <h5>Total size</h5>
139 <span className="text-lg">{currentDiskSize} GB</span>
140 </div>
141
142 {reportsAll && (
143 <div className="col-span-2 mt-4">
144 <Button asChild type="default" iconRight={<ExternalLink size={14} />}>
145 <Link
146 href={`/project/${projectRef}/reports/database#database-size-report`}
147 >
148 View detailed summary
149 </Link>
150 </Button>
151 </div>
152 )}
153 </div>
154
155 <div className="col-span-8">
156 <Alert>
157 <Info size={16} />
158 <AlertTitle>Importing a lot of data?</AlertTitle>
159 <AlertDescription>
160 <Markdown
161 className="max-w-full"
162 content={`
163We auto-scale your disk as you need more storage, but can only do this once every 4 hours.
164If you upload more than 1.5x the current size of your storage, your database will go
165into read-only mode. If you know how big your database is going to be, you can
166manually increase the size here.
167
168Read more about [disk management](${DOCS_URL}/guides/platform/database-size#disk-management) and how to [free up storage space](${DOCS_URL}/guides/platform/database-size#vacuum-operations).
169`}
170 />
171 </AlertDescription>
172 </Alert>
173 </div>
174 </div>
175 </div>
176 </div>
177 </Panel.Content>
178 </Panel>
179 </div>
180 ) : (
181 <Alert>
182 <InfoIcon />
183 <AlertTitle>
184 {hasAccessToDiskSizeConfig === false
185 ? 'Disk size configuration is not available for projects on the Free Plan'
186 : 'Disk size configuration is only available when the spend cap has been disabled'}
187 </AlertTitle>
188 <AlertDescription>
189 {hasAccessToDiskSizeConfig === false ? (
190 <p>
191 If you are intending to use more than 500MB of disk space, then you will need to
192 upgrade to at least the Pro Plan.
193 </p>
194 ) : (
195 <p>
196 If you are intending to use more than 8GB of disk space, then you will need to
197 disable your spend cap.
198 </p>
199 )}
200 <Button asChild type="default" className="mt-3">
201 <Link
202 href={`/org/${organization?.slug}/billing?panel=${
203 hasAccessToDiskSizeConfig === false ? 'subscriptionPlan' : 'costControl'
204 }`}
205 target="_blank"
206 >
207 {hasAccessToDiskSizeConfig === false
208 ? 'Upgrade subscription'
209 : 'Disable spend cap'}
210 </Link>
211 </Button>
212 </AlertDescription>
213 </Alert>
214 )}
215 </PageSectionContent>
216 </PageSection>
217
218 <DiskSizeConfigurationModal
219 visible={showIncreaseDiskSizeModal}
220 loading={isUpdatingDiskSize}
221 hideModal={setShowIncreaseDiskSizeModal}
222 />
223 </>
224 )
225}