Files
supabase/studio/components/layouts/StorageLayout/StorageMenu.tsx
T

182 lines
5.3 KiB
TypeScript

import { FC } from 'react'
import Link from 'next/link'
import { useRouter } from 'next/router'
import { observer } from 'mobx-react-lite'
import { useStore } from 'hooks'
import {
Badge,
Button,
Dropdown,
Menu,
Typography,
IconLoader,
IconMoreVertical,
Alert,
IconEdit,
} from '@supabase/ui'
import Flag from 'components/ui/Flag/Flag'
import ProductMenuItem from 'components/ui/ProductMenu/ProductMenuItem'
import { STORAGE_ROW_STATUS } from 'components/to-be-cleaned/Storage/Storage.constants'
import { useStorageStore } from 'localStores/storageExplorer/StorageExplorerStore'
interface Props {}
const StorageMenu: FC<Props> = () => {
const router = useRouter()
const { ref, bucketId } = router.query
const page = router.pathname.split('/')[4] as undefined | 'policies' | 'settings' | 'usage'
const { ui } = useStore()
const projectRef = ui.selectedProject?.ref
const storageExplorerStore = useStorageStore()
const {
loaded,
buckets,
openCreateBucketModal,
openDeleteBucketModal,
openToggleBucketPublicModal,
} = storageExplorerStore || {}
return (
<Menu type="pills" className="my-6 flex flex-col flex-grow px-5">
<div className="px-2 mb-6">
<Button
block
type="default"
icon={
<div className="text-scale-900">
<IconEdit size={14} />
</div>
}
style={{ justifyContent: 'start' }}
onClick={openCreateBucketModal}
>
New bucket
</Button>
</div>
<div className="space-y-6">
<div className="">
<div>
<Menu.Group title="All buckets" />
{!loaded ? (
<div className="py-2 px-4 flex items-center space-x-2">
<IconLoader className="animate-spin" size={14} strokeWidth={2} />
<span className="text-sm">Loading buckets</span>
</div>
) : (
<>
{buckets.length === 0 && (
<div className="px-2">
<Alert title="No buckets available">
Buckets that you create will appear here
</Alert>
</div>
)}
{buckets.map((bucket: any, idx: number) => {
const isSelected = bucketId === bucket.id
return (
<BucketRow
key={`${idx}_${bucket.id}`}
bucket={bucket}
projectRef={ref}
isSelected={isSelected}
onSelectDeleteBucket={openDeleteBucketModal}
onSelectToggleBucketPublic={openToggleBucketPublicModal}
/>
)
})}
</>
)}
</div>
</div>
<div className="">
<Menu.Group title="Configuration" />
<Flag name="storageSettings">
<Link href={`/project/${projectRef}/storage/settings`}>
<Menu.Item rounded active={page === 'settings'}>
<Typography.Text className="truncate">Settings</Typography.Text>
</Menu.Item>
</Link>
</Flag>
<Link href={`/project/${projectRef}/storage/policies`}>
<Menu.Item rounded active={page === 'policies'}>
<Typography.Text className="truncate">Policies</Typography.Text>
</Menu.Item>
</Link>
<Link href={`/project/${projectRef}/storage/usage`}>
<Menu.Item rounded active={page === 'usage'}>
<Typography.Text className="truncate">Usage</Typography.Text>
</Menu.Item>
</Link>
</div>
</div>
</Menu>
)
}
export default observer(StorageMenu)
const BucketRow = ({
bucket = {},
projectRef = '',
isSelected = false,
onSelectDeleteBucket = () => {},
onSelectToggleBucketPublic = () => {},
}: any) => {
const bucketOptions = [
{
name: 'Delete bucket',
onClick: () => onSelectDeleteBucket(bucket),
},
{
name: bucket.public ? 'Make private' : 'Make public',
onClick: () => onSelectToggleBucketPublic(bucket),
},
]
return (
<ProductMenuItem
key={bucket.id}
name={
<div className="flex items-center space-x-2">
<Typography.Text>{bucket.name}</Typography.Text>
{bucket.public && <Badge color="yellow">Public</Badge>}
</div>
}
url={`/project/${projectRef}/storage/buckets/${bucket.id}`}
isActive={isSelected}
action={
bucket.status === STORAGE_ROW_STATUS.LOADING ? (
<IconLoader className="animate-spin" size={16} strokeWidth={2} />
) : bucket.status === STORAGE_ROW_STATUS.READY ? (
<Dropdown
side="bottom"
align="end"
overlay={[
bucketOptions.map((option) => (
<Dropdown.Item key={option.name} onClick={option.onClick}>
{option.name}
</Dropdown.Item>
)),
]}
>
<Typography.Text>
<IconMoreVertical
className="opacity-0 group-hover:opacity-100"
size="tiny"
strokeWidth={2}
/>
</Typography.Text>
</Dropdown>
) : (
<div />
)
}
/>
)
}