From 60a570892b759f65beb0494bc705bc2854b51338 Mon Sep 17 00:00:00 2001 From: Matthias Kretschmann Date: Fri, 20 Sep 2019 13:51:24 +0200 Subject: [PATCH] more error output in UI --- client/src/hooks/use-ipfs-api.tsx | 4 +- client/src/routes/Publish/Files/Ipfs.test.tsx | 32 ---------- .../Form.module.scss} | 29 +-------- client/src/routes/Publish/Files/Ipfs/Form.tsx | 26 ++++++++ .../Publish/Files/Ipfs/Status.module.scss | 28 +++++++++ .../src/routes/Publish/Files/Ipfs/Status.tsx | 13 ++++ .../routes/Publish/Files/Ipfs/index.test.tsx | 44 ++++++++++++++ .../Files/{Ipfs.tsx => Ipfs/index.tsx} | 59 +++++++------------ .../src/routes/Publish/Files/index.test.tsx | 3 - 9 files changed, 135 insertions(+), 103 deletions(-) delete mode 100644 client/src/routes/Publish/Files/Ipfs.test.tsx rename client/src/routes/Publish/Files/{Ipfs.module.scss => Ipfs/Form.module.scss} (53%) create mode 100644 client/src/routes/Publish/Files/Ipfs/Form.tsx create mode 100644 client/src/routes/Publish/Files/Ipfs/Status.module.scss create mode 100644 client/src/routes/Publish/Files/Ipfs/Status.tsx create mode 100644 client/src/routes/Publish/Files/Ipfs/index.test.tsx rename client/src/routes/Publish/Files/{Ipfs.tsx => Ipfs/index.tsx} (59%) diff --git a/client/src/hooks/use-ipfs-api.tsx b/client/src/hooks/use-ipfs-api.tsx index f15b277..f92c998 100644 --- a/client/src/hooks/use-ipfs-api.tsx +++ b/client/src/hooks/use-ipfs-api.tsx @@ -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('') } } }, []) diff --git a/client/src/routes/Publish/Files/Ipfs.test.tsx b/client/src/routes/Publish/Files/Ipfs.test.tsx deleted file mode 100644 index 791a79b..0000000 --- a/client/src/routes/Publish/Files/Ipfs.test.tsx +++ /dev/null @@ -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 = - - 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] }) - }) -}) diff --git a/client/src/routes/Publish/Files/Ipfs.module.scss b/client/src/routes/Publish/Files/Ipfs/Form.module.scss similarity index 53% rename from client/src/routes/Publish/Files/Ipfs.module.scss rename to client/src/routes/Publish/Files/Ipfs/Form.module.scss index d71a6b3..9e22c1d 100644 --- a/client/src/routes/Publish/Files/Ipfs.module.scss +++ b/client/src/routes/Publish/Files/Ipfs/Form.module.scss @@ -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; - } -} diff --git a/client/src/routes/Publish/Files/Ipfs/Form.tsx b/client/src/routes/Publish/Files/Ipfs/Form.tsx new file mode 100644 index 0000000..c70e86b --- /dev/null +++ b/client/src/routes/Publish/Files/Ipfs/Form.tsx @@ -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 ( +
+ + {children} + +
+ ) +} diff --git a/client/src/routes/Publish/Files/Ipfs/Status.module.scss b/client/src/routes/Publish/Files/Ipfs/Status.module.scss new file mode 100644 index 0000000..5f39cff --- /dev/null +++ b/client/src/routes/Publish/Files/Ipfs/Status.module.scss @@ -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; + } +} diff --git a/client/src/routes/Publish/Files/Ipfs/Status.tsx b/client/src/routes/Publish/Files/Ipfs/Status.tsx new file mode 100644 index 0000000..7475436 --- /dev/null +++ b/client/src/routes/Publish/Files/Ipfs/Status.tsx @@ -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
{message}
+} diff --git a/client/src/routes/Publish/Files/Ipfs/index.test.tsx b/client/src/routes/Publish/Files/Ipfs/index.test.tsx new file mode 100644 index 0000000..9777283 --- /dev/null +++ b/client/src/routes/Publish/Files/Ipfs/index.test.tsx @@ -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 = + 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( + // + // ) + // 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) + // }) +}) diff --git a/client/src/routes/Publish/Files/Ipfs.tsx b/client/src/routes/Publish/Files/Ipfs/index.tsx similarity index 59% rename from client/src/routes/Publish/Files/Ipfs.tsx rename to client/src/routes/Publish/Files/Ipfs/index.tsx index 7a6fccb..c6cd6ed 100644 --- a/client/src/routes/Publish/Files/Ipfs.tsx +++ b/client/src/routes/Publish/Files/Ipfs/index.tsx @@ -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
${fileSizeReceived || 0}/${fileSize}
` ) - }) + }, [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 ( -
- +
{loading ? ( ) : ( @@ -101,12 +90,6 @@ export default function Ipfs({ addFile }: { addFile(url: string): void }) { disabled={!isIpfsReady} /> )} - {ipfsMessage !== '' && ( -
- {ipfsMessage} -
- )} - {ipfsError &&
{ipfsError}
} -
+ ) } diff --git a/client/src/routes/Publish/Files/index.test.tsx b/client/src/routes/Publish/Files/index.test.tsx index 8f47761..850c3c0 100644 --- a/client/src/routes/Publish/Files/index.test.tsx +++ b/client/src/routes/Publish/Files/index.test.tsx @@ -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'))