mirror of
https://github.com/supabase/supabase.git
synced 2026-10-18 15:49:09 +03:00
* inited. added disk config to a new page * add instances * move moar * moved things around. billing badges updated. compute added * tidy * new components * form now dynamically updating itself * updated compute form. moved warning panels. added collapsible for advanced options * review dialog now only showing what is relevant * Update DiskManagementForm.tsx * compute sizes now a reccomendation * fix old form * started adding flags * removed unused code. fixed issue with IOPS price showing on smaller compute * moar clearning * IOPS logic wrong way round * type fixes * start adding better error handling * TIDY * moved everything to own file * tidy * fix hydration issue * moved some components around * clean up * inline errors * update form message * Update DiskManagementForm.tsx * error fields fixed. some formatting issues. nano added as an option * fix constants * add some plan restrictions * moar * units updated. labels updated * Update DiskManagement.schema.ts * fix a ton of type issues * text udpates * add panel to suggest switching to io2 * more notice board stuff * number formatting. moved a file * Update DiskManagementForm.tsx * remove console logs * upgrade comms. more type fixes * add empty states for the old areas * more links * updated some label issues * hide labels when chart is active * Update DiskManagement.utils.ts * Delete next-env.d.ts * Update DiskManagementForm.tsx * Update DiskManagement.schema.ts * text updates * Update DiskManagement.constants.tsx * Update next-env.d.ts * Update next-env.d.ts * Small clean uop * Clean up empty files * Clean up spelling * Clean up more * Fix typo in file name * Clean up import statements * Update DiskManagementForm.tsx * fix issues * Update ProjectLayout.tsx * Remove unused import * Fix * Address nit * Update database.tsx * remove supress toast * Update DiskManagement.schema.ts * Update database.tsx * change upgrade comms * Update DiskManagementPanelForm.tsx * fixes * fix button size on old form * Update DiskManagementForm.tsx * Update StorageTypeField.tsx * update labels on compute * dont show banner when infra is FLY * update comms. hide disk config for FLY * Fix TS * Last round of clean upo * fix message state * fix message * Fix TS * Update DiskManagement.utils.ts * fix errors * Update BillingChangeBadge.tsx * fixed some label issues --------- Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
224 lines
8.7 KiB
TypeScript
224 lines
8.7 KiB
TypeScript
import { AnimatePresence, motion } from 'framer-motion'
|
|
import { Info } from 'lucide-react'
|
|
import MotionNumber from 'motion-number'
|
|
import { UseFormReturn } from 'react-hook-form'
|
|
|
|
import { useParams } from 'common'
|
|
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
|
import { useDiskUtilizationQuery } from 'data/config/disk-utilization-query'
|
|
import { useDatabaseSizeQuery } from 'data/database/database-size-query'
|
|
import { GB } from 'lib/constants'
|
|
import { formatBytes } from 'lib/helpers'
|
|
import {
|
|
badgeVariants,
|
|
cn,
|
|
Tooltip_Shadcn_,
|
|
TooltipContent_Shadcn_,
|
|
TooltipTrigger_Shadcn_,
|
|
} from 'ui'
|
|
import { DiskStorageSchemaType } from '../DiskManagement.schema'
|
|
import { AUTOSCALING_THRESHOLD } from './DiskManagement.constants'
|
|
|
|
interface DiskSpaceBarProps {
|
|
form: UseFormReturn<DiskStorageSchemaType>
|
|
}
|
|
|
|
export default function DiskSpaceBar({ form }: DiskSpaceBarProps) {
|
|
const { ref } = useParams()
|
|
const { formState, watch } = form
|
|
|
|
const {
|
|
data: diskUtil,
|
|
// to do, error handling
|
|
} = useDiskUtilizationQuery({
|
|
projectRef: ref,
|
|
})
|
|
|
|
const usedSize = Math.round(((diskUtil?.metrics.fs_used_bytes ?? 0) / GB) * 100) / 100
|
|
const totalSize = formState.defaultValues?.totalSize || 0
|
|
const show = formState.dirtyFields.totalSize !== undefined && usedSize
|
|
const newTotalSize = watch('totalSize')
|
|
|
|
const usedPercentage = (usedSize / totalSize) * 100
|
|
const resizePercentage = AUTOSCALING_THRESHOLD * 100
|
|
|
|
const newUsedPercentage = (usedSize / newTotalSize) * 100
|
|
const newResizePercentage = AUTOSCALING_THRESHOLD * 100
|
|
|
|
const { project } = useProjectContext()
|
|
const { data } = useDatabaseSizeQuery({
|
|
projectRef: project?.ref,
|
|
connectionString: project?.connectionString,
|
|
})
|
|
|
|
const databaseSizeBytes = data?.result[0].db_size ?? 0
|
|
return (
|
|
<div className="flex flex-col gap-2">
|
|
<div className="flex items-center h-6 gap-3">
|
|
<span className="text-foreground-light text-sm font-mono flex items-center gap-2">
|
|
{usedSize.toFixed(2)}
|
|
<span>GB used of </span>
|
|
<span className="text-foreground font-semibold -mt-[2px]">
|
|
<MotionNumber
|
|
value={newTotalSize}
|
|
style={{ lineHeight: 0.8 }}
|
|
transition={{
|
|
y: { type: 'spring', duration: 0.35, bounce: 0 },
|
|
}}
|
|
className="font-mono"
|
|
/>
|
|
</span>{' '}
|
|
GB
|
|
</span>
|
|
</div>
|
|
<div className="relative">
|
|
<div
|
|
className={cn(
|
|
'h-[35px] relative border rounded-sm w-full transition',
|
|
show ? 'bg-selection border border-brand-button' : 'bg-surface-300'
|
|
)}
|
|
>
|
|
<AnimatePresence>
|
|
{!show ? (
|
|
<motion.div
|
|
key="currentBar"
|
|
initial={{ rotateY: 90, zIndex: 2 }}
|
|
animate={{ rotateY: 0, zIndex: 1 }}
|
|
exit={{ rotateY: -90, zIndex: 2 }}
|
|
transition={{ duration: 0.3 }}
|
|
style={{ transformOrigin: 'left center', backfaceVisibility: 'hidden' }}
|
|
className="absolute inset-0 rounded-sm overflow-hidden"
|
|
>
|
|
<div className="h-full flex">
|
|
<div
|
|
className="bg-foreground relative overflow-hidden transition-all duration-500 ease-in-out"
|
|
style={{ width: `${usedPercentage}%` }}
|
|
>
|
|
<div
|
|
className="absolute inset-0"
|
|
style={{
|
|
backgroundImage: `repeating-linear-gradient(
|
|
-45deg,
|
|
rgba(255,255,255,0.1),
|
|
rgba(255,255,255,0.1) 1px,
|
|
transparent 1px,
|
|
transparent 4px
|
|
)`,
|
|
}}
|
|
/>
|
|
</div>
|
|
<div
|
|
className="bg-transparent border-r transition-all duration-500 ease-in-out"
|
|
style={{ width: `${resizePercentage - usedPercentage}%` }}
|
|
/>
|
|
</div>
|
|
</motion.div>
|
|
) : (
|
|
<motion.div
|
|
key="newBar"
|
|
initial={{ rotateY: -90, zIndex: 2 }}
|
|
animate={{ rotateY: 0, zIndex: 1 }}
|
|
exit={{ rotateY: 90, zIndex: 2 }}
|
|
transition={{ duration: 0.3 }}
|
|
style={{ transformOrigin: 'left center', backfaceVisibility: 'hidden' }}
|
|
className="absolute inset-0 rounded-sm overflow-hidden"
|
|
>
|
|
<div className="h-full flex">
|
|
<div
|
|
className="bg-foreground relative overflow-hidden transition-all duration-500 ease-in-out"
|
|
style={{ width: `${newUsedPercentage}%` }}
|
|
>
|
|
<div
|
|
className="absolute inset-0"
|
|
style={{
|
|
backgroundImage: `repeating-linear-gradient(
|
|
-45deg,
|
|
rgba(255,255,255,0.1),
|
|
rgba(255,255,255,0.1) 1px,
|
|
transparent 1px,
|
|
transparent 4px
|
|
)`,
|
|
}}
|
|
/>
|
|
</div>
|
|
</div>
|
|
</motion.div>
|
|
)}
|
|
</AnimatePresence>
|
|
<AnimatePresence>
|
|
{show && (
|
|
<motion.span
|
|
initial={{ opacity: 0, x: 4 }}
|
|
animate={{ opacity: 1, x: 0 }}
|
|
exit={{ opacity: 0, x: 4 }}
|
|
transition={{
|
|
duration: 0.12,
|
|
delay: 0.12,
|
|
}}
|
|
className={cn(badgeVariants({ variant: 'success' }), 'absolute right-1 top-[5px]')}
|
|
>
|
|
New disk size
|
|
</motion.span>
|
|
)}
|
|
</AnimatePresence>
|
|
</div>
|
|
<AnimatePresence initial={true}>
|
|
{!show && (
|
|
<motion.div
|
|
key="currentSize"
|
|
initial={{ opacity: 0, y: -10 }}
|
|
animate={{ opacity: 1, y: 0 }}
|
|
exit={{ opacity: 0, y: 10 }}
|
|
transition={{ duration: 0.1 }}
|
|
className="absolute h-8 w-full -mx-[2px]"
|
|
>
|
|
<div
|
|
className="absolute top-0 -left-0 h-full flex items-center transition-all duration-500 ease-in-out"
|
|
style={{ left: `${show ? newResizePercentage : resizePercentage}%` }}
|
|
>
|
|
<Tooltip_Shadcn_>
|
|
<TooltipTrigger_Shadcn_ asChild>
|
|
<div className="absolute right-full bottom-0 border mr-2 px-2 py-1 bg-surface-400 rounded text-xs text-foreground-light whitespace-nowrap flex items-center gap-x-1">
|
|
Autoscaling <Info size={12} />
|
|
</div>
|
|
</TooltipTrigger_Shadcn_>
|
|
<TooltipContent_Shadcn_ side="bottom" className="w-[310px] flex flex-col gap-y-1">
|
|
<p>
|
|
Supabase expands your disk storage automatically when the database reached 90%
|
|
of the disk size. However, any disk modifications, including auto-scaling, can
|
|
only take place once every 6 hours.
|
|
</p>
|
|
<p>
|
|
If within those 6 hours you reach 95% of the disk space, your project{' '}
|
|
<span className="text-destructive-600">will enter read-only mode.</span>
|
|
</p>
|
|
</TooltipContent_Shadcn_>
|
|
</Tooltip_Shadcn_>
|
|
<div className="w-px h-full bg-border" />
|
|
</div>
|
|
</motion.div>
|
|
)}
|
|
</AnimatePresence>
|
|
</div>
|
|
{!show && (
|
|
<div className="flex items-center space-x-4 text-xs text-foreground-lighter">
|
|
<div className="flex items-center">
|
|
<div className="w-2 h-2 rounded-full bg-foreground mr-2" />
|
|
<span>Used Space</span>
|
|
</div>
|
|
<div className="flex items-center">
|
|
<div className="w-2 h-2 rounded-full bg-border border border-strong mr-2" />
|
|
<span>Available space</span>
|
|
</div>
|
|
</div>
|
|
)}
|
|
<p className="text-xs text-foreground-lighter my-4">
|
|
<span className="font-semibold">Note:</span> Disk Size refers to the total space your
|
|
project occupies on disk, including the database itself (currently{' '}
|
|
<span>{formatBytes(databaseSizeBytes, 2, 'GB')}</span>), additional files like the
|
|
write-ahead log (WAL), and other internal resources.
|
|
</p>
|
|
</div>
|
|
)
|
|
}
|