Skip to content

Commit

Permalink
feat: renterd bucket support
Browse files Browse the repository at this point in the history
  • Loading branch information
alexfreska committed Sep 20, 2023
1 parent de6572a commit c9e88bc
Show file tree
Hide file tree
Showing 47 changed files with 1,046 additions and 710 deletions.
5 changes: 5 additions & 0 deletions .changeset/calm-oranges-think.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@siafoundation/react-renterd': minor
---

Added useBuckets, useBucketCreate, useBucketDelete, and bucket support to all object hooks.
5 changes: 5 additions & 0 deletions .changeset/fuzzy-ears-pay.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'renterd': minor
---

The not enough active contracts warning no longer flickers.
5 changes: 5 additions & 0 deletions .changeset/khaki-pianos-cry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'renterd': minor
---

The files feature now supports buckets.
125 changes: 59 additions & 66 deletions apps/explorer/components/Home/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,38 +35,17 @@ export function Home({
hosts: SiaCentralHost[]
rates: SiaCentralExchangeRates
}) {
const exchange = useExchangeRate()
const exchange = useExchangeRate(rates)
const values = useMemo(() => {
const list = [
{
label: 'Blockchain height',
value: (
<div className="flex flex-col sm:flex-row gap-1 items-baseline">
{humanNumber(blockHeight)}
{/* {status.data &&
status.data.consensusblock !== status.data.lastblock && (
<>
<Text
scaleSize="20"
color="subtle"
className="hidden sm:block"
>
/
</Text>
<Tooltip
content={`${humanNumber(
status.data?.lastblock
)} / ${humanNumber(
status.data?.consensusblock
)} of consensus height synced`}
>
<Text size="20" font="mono" color="subtle">
{humanNumber(status.data?.consensusblock)}
</Text>
</Tooltip>
</>
)} */}
</div>
<Tooltip content="Block height">
<Text scaleSize="20" color="subtle">
{humanNumber(blockHeight)}
</Text>
</Tooltip>
),
},
{
Expand Down Expand Up @@ -133,50 +112,71 @@ export function Home({
label: 'Average storage price',
value: (
<Tooltip content="Average storage price per TB/month">
<Text
className="text-xl md:text-3xl"
weight="semibold"
color="contrast"
>
{getStorageCost({
price: metrics?.average.settings.storage_price,
exchange,
})}
</Text>
<div className="flex flex-col gap-1">
<Text
className="text-xl md:text-3xl"
weight="semibold"
color="contrast"
>
{getStorageCost({
price: metrics?.average.settings.storage_price,
exchange,
})}
</Text>
<Text color="subtle" className="text-end">
{getStorageCost({
price: metrics?.average.settings.storage_price,
})}
</Text>
</div>
</Tooltip>
),
},
{
label: 'Average download price',
value: (
<Tooltip content="Average download price per TB">
<Text
className="text-xl md:text-3xl"
weight="semibold"
color="contrast"
>
{getDownloadCost({
price: metrics?.average.settings.download_price,
exchange,
})}
</Text>
<div className="flex flex-col gap-1">
<Text
className="text-xl md:text-3xl"
weight="semibold"
color="contrast"
>
{getDownloadCost({
price: metrics?.average.settings.download_price,
exchange,
})}
</Text>
<Text color="subtle" className="text-end">
{getDownloadCost({
price: metrics?.average.settings.download_price,
})}
</Text>
</div>
</Tooltip>
),
},
{
label: 'Average upload price',
value: (
<Tooltip content="Average upload price per TB">
<Text
className="text-xl md:text-3xl"
weight="semibold"
color="contrast"
>
{getUploadCost({
price: metrics?.average.settings.upload_price,
exchange,
})}
</Text>
<div className="flex flex-col gap-1">
<Text
className="text-xl md:text-3xl"
weight="semibold"
color="contrast"
>
{getUploadCost({
price: metrics?.average.settings.upload_price,
exchange,
})}
</Text>
<Text color="subtle" className="text-end">
{getUploadCost({
price: metrics?.average.settings.upload_price,
})}
</Text>
</div>
</Tooltip>
),
},
Expand All @@ -187,7 +187,7 @@ export function Home({
return (
<ContentLayout
panel={
<div className="grid grid-cols-3 gap-x-6 md:gap-x-12 gap-y-12">
<div className="grid grid-cols-2 md:grid-cols-3 gap-x-6 md:gap-x-12 gap-y-12">
{values.map(({ label, value }) => (
<div
className="flex flex-col gap-6 items-start overflow-hidden"
Expand All @@ -196,14 +196,7 @@ export function Home({
<Text color="subtle" scaleSize="14" className="w-full" ellipsis>
{label}
</Text>
<Text
font="mono"
weight="semibold"
className="text-xl md:text-3xl"
ellipsis
>
{value}
</Text>
{value}
</div>
))}
</div>
Expand Down
14 changes: 7 additions & 7 deletions apps/explorer/components/HomeSkeleton/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ export function HomeSkeleton() {
return (
<ContentLayout
panel={
<div className="grid grid-cols-3 gap-x-6 md:gap-x-12 gap-y-12">
<Skeleton className="w-full h-[85px] sm:w-[180px] sm:h-[62px]" />
<Skeleton className="w-full h-[85px] sm:w-[180px] sm:h-[62px]" />
<Skeleton className="w-full h-[85px] sm:w-[180px] sm:h-[62px]" />
<Skeleton className="w-full h-[85px] sm:w-[180px] sm:h-[62px]" />
<Skeleton className="w-full h-[85px] sm:w-[180px] sm:h-[62px]" />
<Skeleton className="w-full h-[85px] sm:w-[180px] sm:h-[62px]" />
<div className="grid grid-cols-2 md:grid-cols-3 gap-x-6 md:gap-x-12 gap-y-12">
<Skeleton className="w-full h-[105px] sm:w-[180px] sm:h-[62px]" />
<Skeleton className="w-full h-[105px] sm:w-[180px] sm:h-[62px]" />
<Skeleton className="w-full h-[105px] sm:w-[180px] sm:h-[62px]" />
<Skeleton className="w-full h-[150px] sm:w-[180px] sm:h-[80px]" />
<Skeleton className="w-full h-[150px] sm:w-[180px] sm:h-[80px]" />
<Skeleton className="w-full h-[150px] sm:w-[180px] sm:h-[80px]" />
</div>
}
>
Expand Down
6 changes: 3 additions & 3 deletions apps/explorer/lib/host.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export function getStorageCost({ price, exchange }: Props) {
.times(monthsToBlocks(1))
.div(1e24)
.times(exchange.rate || 1)
.toFixed(2)}/TB`
.toFormat(2)}/TB`
: `${humanSiacoin(
new BigNumber(price).times(TBToBytes(1)).times(monthsToBlocks(1)),
{ fixed: 3 }
Expand All @@ -32,7 +32,7 @@ export function getDownloadCost({ price, exchange }: Props) {
.times(TBToBytes(1))
.div(1e24)
.times(exchange.rate || 1)
.toFixed(2)}/TB`
.toFormat(2)}/TB`
: `${humanSiacoin(new BigNumber(price).times(TBToBytes(1)), {
fixed: 3,
})}/TB`
Expand All @@ -44,7 +44,7 @@ export function getUploadCost({ price, exchange }: Props) {
.times(TBToBytes(1))
.div(1e24)
.times(exchange.rate || 1)
.toFixed(2)}/TB`
.toFormat(2)}/TB`
: `${humanSiacoin(new BigNumber(price).times(TBToBytes(1)), {
fixed: 3,
})}/TB`
Expand Down
41 changes: 41 additions & 0 deletions apps/renterd/components/Files/BucketContextMenu.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import {
DropdownMenu,
DropdownMenuItem,
Button,
DropdownMenuLeftSlot,
Delete16,
DropdownMenuLabel,
BucketIcon,
} from '@siafoundation/design-system'
import { useDialog } from '../../contexts/dialog'

type Props = {
name: string
}

export function BucketContextMenu({ name }: Props) {
const { openDialog } = useDialog()
return (
<DropdownMenu
trigger={
<Button variant="ghost" icon="hover">
<BucketIcon size={16} />
</Button>
}
contentProps={{ align: 'start' }}
>
<DropdownMenuLabel>Actions</DropdownMenuLabel>
<DropdownMenuItem
disabled={name === 'default'}
onSelect={() => {
openDialog('filesDeleteBucket', name)
}}
>
<DropdownMenuLeftSlot>
<Delete16 />
</DropdownMenuLeftSlot>
Delete bucket
</DropdownMenuItem>
</DropdownMenu>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,19 @@ import { sortBy } from 'lodash'
import { computeSlabContractSetShards } from '../../../../contexts/files/health'
import { ObjectData } from '../../../../contexts/files/types'
import { useHealthLabel } from '../../../../hooks/useHealthLabel'
import { bucketAndKeyParamsFromPath } from '../../../../contexts/files/paths'

export function FilesHealthColumnContents({
path,
isUploading,
isDirectory,
type,
health: _health,
size,
}: ObjectData) {
const isDirectory = type === 'directory'
const obj = useObject({
disabled: isUploading || isDirectory,
params: {
key: path.slice(1),
},
params: bucketAndKeyParamsFromPath(path),
config: {
swr: {
dedupingInterval: 5000,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import { useHealthLabel } from '../../../../hooks/useHealthLabel'
import { FilesHealthColumnContents } from './FilesHealthColumnContents'

export function FilesHealthColumn(props: ObjectData) {
const { name, isUploading, isDirectory, health: _health, size } = props
const { name, isUploading, type, health: _health, size } = props
const isDirectory = type === 'directory'
const { displayHealth, label, color, icon } = useHealthLabel({
health: _health,
size,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { CloudUpload32, LinkButton, Text } from '@siafoundation/design-system'
import { routes } from '../../config/routes'
import { useFiles } from '../../contexts/files'
import { useAutopilotNotConfigured } from './checks/useAutopilotNotConfigured'
import { useNotEnoughContracts } from './checks/useNotEnoughContracts'
import { routes } from '../../../config/routes'
import { useFiles } from '../../../contexts/files'
import { useAutopilotNotConfigured } from '../checks/useAutopilotNotConfigured'
import { useNotEnoughContracts } from '../checks/useNotEnoughContracts'
import { StateError } from './StateError'
import { StateNoneMatching } from './StateNoneMatching'
import { StateNoneYet } from './StateNoneYet'

export function EmptyState() {
const { dataState, activeDirectoryPath } = useFiles()
const { dataState, isViewingRootOfABucket } = useFiles()

const autopilotNotConfigured = useAutopilotNotConfigured()
const notEnoughContracts = useNotEnoughContracts()
Expand All @@ -23,7 +23,7 @@ export function EmptyState() {

// only show on root directory and when there are no files
if (
activeDirectoryPath === '/' &&
isViewingRootOfABucket &&
dataState === 'noneYet' &&
autopilotNotConfigured.active
) {
Expand All @@ -48,7 +48,7 @@ export function EmptyState() {

// only show on root directory and when there are no files
if (
activeDirectoryPath === '/' &&
isViewingRootOfABucket &&
dataState === 'noneYet' &&
notEnoughContracts.active
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
Copy16,
} from '@siafoundation/design-system'
import { useObject } from '@siafoundation/react-renterd'
import { bucketAndKeyParamsFromPath } from '../../../contexts/files/paths'

type Props = {
path: string
Expand All @@ -14,9 +15,7 @@ type Props = {
// specific one when the user triggers the context menu.
export function CopyMetadataMenuItem({ path }: Props) {
const obj = useObject({
params: {
key: path.slice(1),
},
params: bucketAndKeyParamsFromPath(path),
config: {
swr: {
dedupingInterval: 5000,
Expand Down
5 changes: 2 additions & 3 deletions apps/renterd/components/Files/FileContextMenu/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,10 @@ import { useFileDelete } from '../useFileDelete'
import { CopyMetadataMenuItem } from './CopyMetadataMenuItem'

type Props = {
name: string
path: string
}

export function FileContextMenu({ name, path }: Props) {
export function FileContextMenu({ path }: Props) {
const { downloadFiles, getFileUrl } = useFiles()
const deleteFile = useFileDelete()

Expand All @@ -39,7 +38,7 @@ export function FileContextMenu({ name, path }: Props) {
<DropdownMenuLabel>Actions</DropdownMenuLabel>
<DropdownMenuItem
onSelect={async () => {
downloadFiles([name])
downloadFiles([path])
}}
>
<DropdownMenuLeftSlot>
Expand Down
Loading

0 comments on commit c9e88bc

Please sign in to comment.