more error output in UI

This commit is contained in:
Matthias Kretschmann 2019-09-20 13:51:24 +02:00
parent 483cc35de3
commit 60a570892b
Signed by: m
GPG Key ID: 606EEEF3C479A91F
9 changed files with 135 additions and 103 deletions

View File

@ -15,7 +15,7 @@ export interface IpfsConfig {
export default function useIpfsApi(config: IpfsConfig) {
const [isIpfsReady, setIpfsReady] = useState(Boolean(ipfs))
const [ipfsError, setIpfsError] = useState(null)
const [ipfsError, setIpfsError] = useState('')
useEffect(() => {
async function initIpfs() {
@ -49,7 +49,7 @@ export default function useIpfsApi(config: IpfsConfig) {
ipfs = null
ipfsMessage = ''
ipfsVersion = ''
setIpfsError(null)
setIpfsError('')
}
}
}, [])

View File

@ -1,32 +0,0 @@
import React from 'react'
import { render, fireEvent } from '@testing-library/react'
import Ipfs from './Ipfs'
const addFile = jest.fn()
describe('Ipfs', () => {
const ui = <Ipfs addFile={addFile} />
it('renders without crashing', async () => {
const { container, findByText } = render(ui)
expect(container.firstChild).toBeInTheDocument()
// wait for IPFS node
await findByText(/Connected to /)
})
it('files can be dropped', async () => {
const { container, findByText } = render(ui)
// wait for IPFS node
await findByText(/Connected to /)
const file = new File(['(⌐□_□)'], 'chucknorris.png', {
type: 'image/png'
})
// drop a file
const dropzoneInput = container.querySelector('.dropzone input')
dropzoneInput && fireEvent.change(dropzoneInput, { target: [file] })
})
})

View File

@ -1,4 +1,4 @@
@import '../../../styles/variables';
@import '../../../../styles/variables';
.ipfsForm {
margin-top: $spacer / 2;
@ -23,30 +23,3 @@
}
}
}
.message {
font-size: $font-size-small;
margin-top: $spacer / 2;
color: $brand-grey-light;
&:before {
content: '';
width: .5rem;
height: .5rem;
display: inline-block;
background: $green;
border-radius: 50%;
margin-right: $spacer / 4;
margin-bottom: .05rem;
}
}
.error {
composes: message;
color: $red;
&:before {
border-radius: 0;
background: $red;
}
}

View File

@ -0,0 +1,26 @@
import React from 'react'
import Label from '../../../../components/atoms/Form/Label'
import Status from './Status'
import styles from './Form.module.scss'
export default function Form({
children,
ipfsMessage,
ipfsError,
error
}: {
children: any
ipfsMessage: string
ipfsError?: string
error?: string
}) {
return (
<div className={styles.ipfsForm}>
<Label htmlFor="fileUpload" required>
Add File To IPFS
</Label>
{children}
<Status message={ipfsMessage} error={ipfsError || error} />
</div>
)
}

View File

@ -0,0 +1,28 @@
@import '../../../../styles/variables';
.message {
font-size: $font-size-small;
margin-top: $spacer / 2;
color: $brand-grey-light;
&:before {
content: '';
width: .5rem;
height: .5rem;
display: inline-block;
background: $green;
border-radius: 50%;
margin-right: $spacer / 4;
margin-bottom: .05rem;
}
}
.error {
composes: message;
color: $red;
&:before {
border-radius: 0;
background: $red;
}
}

View File

@ -0,0 +1,13 @@
import React from 'react'
import styles from './Status.module.scss'
export default function Status({
message,
error
}: {
message: string
error?: string
}) {
const classes = error ? styles.error : styles.message
return <div className={classes}>{message}</div>
}

View File

@ -0,0 +1,44 @@
import React from 'react'
import { render, fireEvent, waitForElement, act } from '@testing-library/react'
import Ipfs from '.'
const addFile = jest.fn()
describe('IPFS', () => {
const ui = <Ipfs addFile={addFile} />
const file = new File(['(⌐□_□)'], 'chucknorris.png', {
type: 'image/png'
})
it('HTTP API: files can be dropped', async () => {
const { container, findByText, getByText } = render(ui)
expect(container).toBeInTheDocument()
// wait for IPFS node
await findByText(/Connected to /)
// drop a file
const dropzoneInput = container.querySelector('.dropzone')
Object.defineProperty(dropzoneInput, 'files', { value: [file] })
act(() => {
dropzoneInput && fireEvent.drop(dropzoneInput)
})
const addingText = await waitForElement(() => getByText(/Adding /))
expect(addingText).toBeDefined()
})
// it('Local Node: files can be dropped', async () => {
// const { debug, container, findByText, getByText } = render(
// <Ipfs addFile={addFile} node />
// )
// expect(container).toBeInTheDocument()
// // wait for IPFS node
// await findByText(/IPFS started/)
// // drop a file
// const dropzoneInput = container.querySelector('.dropzone input')
// Object.defineProperty(dropzoneInput, 'files', { value: [file] })
// dropzoneInput && fireEvent.drop(dropzoneInput)
// await waitForElement(() => getByText(/File found/), { timeout: 100000 })
// expect(addFile).toHaveBeenCalledTimes(1)
// })
})

View File

@ -1,12 +1,11 @@
/* eslint-disable no-console */
import React, { useState, useEffect } from 'react'
import useIpfsApi, { IpfsConfig } from '../../../hooks/use-ipfs-api'
import Label from '../../../components/atoms/Form/Label'
import Spinner from '../../../components/atoms/Spinner'
import Dropzone from '../../../components/molecules/Dropzone'
import { formatBytes, pingUrl, readFileAsync } from '../../../utils/utils'
import { ipfsGatewayUri } from '../../../config'
import styles from './Ipfs.module.scss'
import useIpfsApi, { IpfsConfig } from '../../../../hooks/use-ipfs-api'
import Spinner from '../../../../components/atoms/Spinner'
import Dropzone from '../../../../components/molecules/Dropzone'
import { formatBytes, pingUrl, readFileAsync } from '../../../../utils/utils'
import { ipfsGatewayUri } from '../../../../config'
import Form from './Form'
const config: IpfsConfig = {
host: 'ipfs.infura.io',
@ -15,34 +14,26 @@ const config: IpfsConfig = {
}
export default function Ipfs({ addFile }: { addFile(url: string): void }) {
const {
ipfs,
ipfsVersion,
isIpfsReady,
ipfsError,
ipfsMessage
} = useIpfsApi(config)
const { ipfs, isIpfsReady, ipfsError, ipfsMessage } = useIpfsApi(config)
const [loading, setLoading] = useState(false)
const [message, setMessage] = useState('')
const [fileSize, setFileSize] = useState('')
const [fileSizeReceived, setFileSizeReceived] = useState('')
const [error, setError] = useState('')
useEffect(() => {
setMessage(
`Adding to IPFS<br />
<small>${fileSizeReceived || 0}/${fileSize}</small><br />`
)
})
}, [fileSize, fileSizeReceived])
async function addToIpfs(data: any) {
try {
const response = await ipfs.add(data, {
wrapWithDirectory: true,
progress: (length: number) => {
console.log(`Received: ${formatBytes(length, 0)}`)
progress: (length: number) =>
setFileSizeReceived(formatBytes(length, 0))
}
})
// CID of wrapping directory is returned last
@ -50,25 +41,26 @@ export default function Ipfs({ addFile }: { addFile(url: string): void }) {
console.log(`File added: ${cid}`)
return cid
} catch (error) {
console.error(`Adding to IPFS failed: ${error.message}`)
setError(`Adding to IPFS failed: ${error.message}`)
setLoading(false)
}
}
async function handleOnDrop(acceptedFiles: File[]) {
async function handleOnDrop(acceptedFiles: any) {
if (!acceptedFiles[0]) return
const { name, size } = acceptedFiles[0]
const totalSize = formatBytes(size, 0)
setLoading(true)
setError('')
const { path, size } = acceptedFiles[0]
const totalSize = formatBytes(size, 0)
setFileSize(totalSize)
// Add file to IPFS node
const content: any = await readFileAsync(acceptedFiles[0])
const data = Buffer.from(content)
const fileDetails = {
path: name,
path,
content: data
}
@ -77,8 +69,8 @@ export default function Ipfs({ addFile }: { addFile(url: string): void }) {
// Ping gateway url to make it globally available,
// but store native url in DDO.
const urlGateway = `${ipfsGatewayUri}/ipfs/${cid}/${name}`
const url = `ipfs://${cid}/${name}`
const urlGateway = `${ipfsGatewayUri}/ipfs/${cid}/${path}`
const url = `ipfs://${cid}/${path}`
setMessage('Checking IPFS gateway URL')
await pingUrl(urlGateway)
@ -88,10 +80,7 @@ export default function Ipfs({ addFile }: { addFile(url: string): void }) {
}
return (
<div className={styles.ipfsForm}>
<Label htmlFor="fileUpload" required>
Add File To IPFS
</Label>
<Form error={error} ipfsMessage={ipfsMessage} ipfsError={ipfsError}>
{loading ? (
<Spinner message={message} />
) : (
@ -101,12 +90,6 @@ export default function Ipfs({ addFile }: { addFile(url: string): void }) {
disabled={!isIpfsReady}
/>
)}
{ipfsMessage !== '' && (
<div className={styles.message} title={ipfsVersion}>
{ipfsMessage}
</div>
)}
{ipfsError && <div className={styles.error}>{ipfsError}</div>}
</div>
</Form>
)
}

View File

@ -74,9 +74,6 @@ describe('Files', () => {
await waitForElement(() => getByText('- Cancel'))
expect(container.querySelector('.ipfsForm')).toBeInTheDocument()
// wait for IPFS node
await findByText(/Connected to /)
// close
fireEvent.click(getByText('- Cancel'))
await waitForElement(() => getByText('+ Add to IPFS'))