Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

renterd onboarding, network and build version, migrate slab alert objects, and more #353

Merged
merged 8 commits into from
Aug 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/cyan-dots-cover.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@siafoundation/react-renterd': minor
---

useObject now includes partialSlab.
5 changes: 5 additions & 0 deletions .changeset/dull-readers-sit.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'renterd': minor
---

File upload and directory creation are now disabled until enough contracts are formed.
5 changes: 5 additions & 0 deletions .changeset/eight-wombats-sneeze.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'hostd': minor
---

Fixed an issue where alert error messages were being cut off. Full error messages are now displayed above all other fields.
5 changes: 5 additions & 0 deletions .changeset/happy-hornets-tickle.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'renterd': minor
---

The failed to migrate slab alert now lists the associated objects/files.
5 changes: 5 additions & 0 deletions .changeset/odd-pillows-try.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'renterd': minor
---

New users are now more clearly instructed to configure autopilot and to wait for enough contracts before files can be uploaded.
5 changes: 5 additions & 0 deletions .changeset/plenty-baboons-leave.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'renterd': minor
---

Node profile information now includes the build version.
5 changes: 5 additions & 0 deletions .changeset/pretty-rules-bake.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@siafoundation/react-renterd': minor
---

Add useSlabObjects.
5 changes: 5 additions & 0 deletions .changeset/six-mice-work.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@siafoundation/react-renterd': minor
---

Add useAutopilotState, useBusState, useWorkerState, remove useAutopilotStatus.
7 changes: 7 additions & 0 deletions .changeset/slimy-stingrays-ring.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'hostd': minor
'renterd': minor
'walletd': minor
---

The connectivity and login check no longer depends on consensus APIs which in some rare cases can be unresponsive.
5 changes: 5 additions & 0 deletions .changeset/smart-scissors-help.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'renterd': minor
---

Alerts now show contract additions and removals, formatted address, balance, and more.
5 changes: 5 additions & 0 deletions .changeset/wise-phones-bathe.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'renterd': minor
---

File health tooltip now includes redundancy info and supports partial slabs.
4 changes: 3 additions & 1 deletion apps/hostd/config/routes.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { stateHostKey } from '@siafoundation/react-hostd'

export const routes = {
home: '/',
volumes: {
Expand All @@ -20,4 +22,4 @@ export const routes = {
login: '/login',
}

export const connectivityRoute = '/state/consensus'
export const connectivityRoute = stateHostKey
16 changes: 12 additions & 4 deletions apps/hostd/dialogs/AlertsDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
import { useAlerts, useAlertsDismiss } from '@siafoundation/react-hostd'
import { humanDate, humanTime } from '@siafoundation/sia-js'
import { cx } from 'class-variance-authority'
import { times } from 'lodash'
import { difference, times } from 'lodash'
import { useCallback } from 'react'

type Props = {
Expand Down Expand Up @@ -142,6 +142,11 @@ export function AlertsDialog({ open, onOpenChange }: Props) {
<Checkmark16 />
</Button>
</div>
{!!a.data.error && (
<Text color="contrast" className="mb-1">
{a.data.error}
</Text>
)}
<div className="flex justify-between w-full">
<Text color="subtle" ellipsis>
timestamp
Expand All @@ -150,7 +155,7 @@ export function AlertsDialog({ open, onOpenChange }: Props) {
{humanDate(a.timestamp, { timeStyle: 'medium' })}
</Text>
</div>
{getOrderedKeys(a.data).map((key) => {
{getOrderedKeys(a.data, skipFields).map((key) => {
const value = a.data[key]
if (value === undefined) {
return null
Expand All @@ -177,6 +182,8 @@ export function AlertsDialog({ open, onOpenChange }: Props) {
)
}

const skipFields = ['error']

const dataFieldOrder = [
'contractID',
'blockHeight',
Expand All @@ -199,8 +206,8 @@ const dataFieldOrder = [
]

// Sort keys by dataFieldOrder, then alphabetically
function getOrderedKeys(obj) {
return Object.keys(obj).sort((a, b) => {
function getOrderedKeys(obj, skip: string[]) {
const keys = Object.keys(obj).sort((a, b) => {
const aIndex = dataFieldOrder.indexOf(a)
const bIndex = dataFieldOrder.indexOf(b)
if (aIndex === -1 && bIndex === -1) {
Expand All @@ -214,6 +221,7 @@ function getOrderedKeys(obj) {
}
return aIndex - bIndex
})
return difference(keys, skip)
}

const dataFields = {
Expand Down
2 changes: 1 addition & 1 deletion apps/renterd/components/CmdRoot/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ export function CmdRoot({ panel }: Props) {
afterSelect()
}}
/>
{autopilot.state === 'on' && (
{autopilot.status === 'on' && (
<AutopilotCmdGroup currentPage={page} pushPage={pushPage} />
)}
<WalletCmdGroup currentPage={page} pushPage={pushPage} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,27 +66,44 @@ export function FilesHealthColumnContents({
'contractSetShards'
)

const { partialSlab } = obj.data.object

return (
<Layout
className={slabs.length > 15 ? 'h-[300px]' : ''}
displayHealth={displayHealth}
label={label}
minShards={partialSlab ? partialSlab.minShards : slabs[0]?.minShards}
totalShards={
partialSlab ? partialSlab.totalShards : slabs[0]?.shards.length
}
>
{slabs.map((slab) => (
<div key={slab.key} className="flex justify-between gap-2">
<Text
size="12"
color="subtle"
className="flex items-center"
font="mono"
>
Slab {slab.key.replace('key:', '').slice(0, 4)}:
</Text>
<Text size="12" className="flex items-center">
{slab.contractSetShards}/{slab.shards.length}
</Text>
</div>
))}
{partialSlab ? (
<Text
size="12"
color="verySubtle"
className="flex items-center justify-center my-2"
font="mono"
>
partial slab
</Text>
) : (
slabs.map((slab) => (
<div key={slab.key} className="flex justify-between gap-2">
<Text
size="12"
color="subtle"
className="flex items-center"
font="mono"
>
Slab {slab.key.replace('key:', '').slice(0, 4)}:
</Text>
<Text size="12" className="flex items-center">
{slab.contractSetShards}/{slab.shards.length}
</Text>
</div>
))
)}
</Layout>
)
}
Expand All @@ -96,11 +113,15 @@ function Layout({
displayHealth,
label,
children,
minShards,
totalShards,
}: {
className?: string
children: React.ReactNode
displayHealth: number
label: string
minShards?: number
totalShards?: number
}) {
return (
<div
Expand All @@ -110,6 +131,16 @@ function Layout({
<Text size="12">{label}</Text>
<Text size="12">{(displayHealth * 100).toFixed(0)}%</Text>
</div>
{minShards && totalShards ? (
<div className="flex justify-between gap-2 pt-0.5 pb-px px-2">
<Text size="12" color="subtle">
redundancy
</Text>
<Text size="12" color="subtle">
{minShards} of {totalShards}
</Text>
</div>
) : null}
<div className="px-2">
<Separator className="w-full my-1" />
</div>
Expand Down
79 changes: 79 additions & 0 deletions apps/renterd/components/Files/EmptyState.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
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 { StateError } from './StateError'
import { StateNoneMatching } from './StateNoneMatching'
import { StateNoneYet } from './StateNoneYet'

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

const autopilotNotConfigured = useAutopilotNotConfigured()
const notEnoughContracts = useNotEnoughContracts()

if (dataState === 'noneMatchingFilters') {
return <StateNoneMatching />
}

if (dataState === 'error') {
return <StateError />
}

// only show on root directory and when there are no files
if (
activeDirectoryPath === '/' &&
dataState === 'noneYet' &&
autopilotNotConfigured.active
) {
return (
<div className="flex flex-col gap-10 justify-center items-center h-[400px] cursor-pointer">
<Text>
<CloudUpload32 className="scale-[200%]" />
</Text>
<div className="flex flex-col gap-6 justify-center items-center">
<Text color="subtle" className="text-center max-w-[500px]">
Before you can upload files you must configure autopilot. Autopilot
finds contracts with hosts based on the settings you choose.
Autopilot also repairs your data as hosts come and go.
</Text>
<LinkButton variant="accent" href={routes.autopilot.index}>
Configure autopilot →
</LinkButton>
</div>
</div>
)
}

// only show on root directory and when there are no files
if (
activeDirectoryPath === '/' &&
dataState === 'noneYet' &&
notEnoughContracts.active
) {
return (
<div className="flex flex-col gap-12 justify-center items-center h-[400px] cursor-pointer">
<Text>
<CloudUpload32 className="scale-[200%]" />
</Text>
<div className="flex flex-col gap-4 justify-center items-center">
<Text color="subtle" className="text-center max-w-[500px]">
There are not enough contracts to upload data yet. Redundancy is
configured to use {notEnoughContracts.required} shards which means
at least that many contracts are required.
</Text>
<Text size="30" className="text-center max-w-[500px]">
{notEnoughContracts.count}/{notEnoughContracts.required}
</Text>
</div>
</div>
)
}

if (dataState === 'noneYet') {
return <StateNoneYet />
}

return null
}
7 changes: 6 additions & 1 deletion apps/renterd/components/Files/FilesActionsMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,17 @@ import { useFiles } from '../../contexts/files'
import { useDropzone } from 'react-dropzone'
import { FilesViewDropdownMenu } from './FilesViewDropdownMenu'
import { useDialog } from '../../contexts/dialog'
import { useCanUpload } from './useCanUpload'

export function FilesActionsMenu() {
const { openDialog } = useDialog()
const { uploadFiles } = useFiles()

const canUpload = useCanUpload()

const { getRootProps, getInputProps } = useDropzone({
noDrag: true,
noClick: !canUpload,
onDrop: uploadFiles,
})

Expand All @@ -23,11 +27,12 @@ export function FilesActionsMenu() {
<Button onClick={() => openDialog('filesSearch')} tip="Search files">
<Search16 />
</Button>
<Button {...getRootProps()} tip="Upload files">
<Button {...getRootProps()} tip="Upload files" disabled={!canUpload}>
<input {...getInputProps()} />
<CloudUpload16 />
</Button>
<Button
disabled={!canUpload}
onClick={() => openDialog('filesCreateDirectory')}
tip="Create directory"
>
Expand Down
22 changes: 9 additions & 13 deletions apps/renterd/components/Files/FilesExplorer.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { Table, Dropzone } from '@siafoundation/design-system'
import { useFiles } from '../../contexts/files'
import { StateError } from './StateError'
import { StateNoneMatching } from './StateNoneMatching'
import { StateNoneYet } from './StateNoneYet'
import { EmptyState } from './EmptyState'
import { useCanUpload } from './useCanUpload'

export function FilesExplorer() {
const {
Expand All @@ -16,20 +15,17 @@ export function FilesExplorer() {
sortableColumns,
toggleSort,
} = useFiles()
const canUpload = useCanUpload()
return (
<div className="relative">
<Dropzone onDrop={uploadFiles} noClick={pageCount > 0}>
<Dropzone
onDrop={uploadFiles}
noClick={!canUpload || pageCount > 0}
noDrag={!canUpload}
>
<Table
isLoading={dataState === 'loading'}
emptyState={
dataState === 'noneMatchingFilters' ? (
<StateNoneMatching />
) : dataState === 'noneYet' ? (
<StateNoneYet />
) : dataState === 'error' ? (
<StateError />
) : null
}
emptyState={<EmptyState />}
pageSize={10}
data={datasetPage}
columns={columns}
Expand Down
Loading