mirror of
https://github.com/oceanprotocol/commons.git
synced 2023-03-15 18:03:00 +01:00
add default env vars into CONNECTIONS cofig
This commit is contained in:
parent
b4fc9883e2
commit
ab342b3fa6
@ -9,28 +9,28 @@ import './styles/global.scss'
|
||||
import styles from './App.module.scss'
|
||||
|
||||
export default class App extends Component {
|
||||
public render() {
|
||||
return (
|
||||
<div className={styles.app}>
|
||||
<Router>
|
||||
<>
|
||||
<Header />
|
||||
public render() {
|
||||
return (
|
||||
<div className={styles.app}>
|
||||
<Router>
|
||||
<>
|
||||
<Header />
|
||||
|
||||
<main className={styles.main}>
|
||||
{this.context.isLoading ? (
|
||||
<div className={styles.loader}>
|
||||
<Spinner message={this.context.message} />
|
||||
</div>
|
||||
) : (
|
||||
<Routes />
|
||||
)}
|
||||
</main>
|
||||
<Footer />
|
||||
</>
|
||||
</Router>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
<main className={styles.main}>
|
||||
{this.context.isLoading ? (
|
||||
<div className={styles.loader}>
|
||||
<Spinner message={this.context.message} />
|
||||
</div>
|
||||
) : (
|
||||
<Routes />
|
||||
)}
|
||||
</main>
|
||||
<Footer />
|
||||
</>
|
||||
</Router>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
App.contextType = User
|
||||
|
@ -8,34 +8,34 @@ import menu from '../../data/menu'
|
||||
import meta from '../../data/meta.json'
|
||||
|
||||
const MenuItem = ({ item }: { item: any }) => (
|
||||
<NavLink
|
||||
to={item.link}
|
||||
className={styles.link}
|
||||
activeClassName={styles.linkActive}
|
||||
exact
|
||||
>
|
||||
{item.title}
|
||||
</NavLink>
|
||||
<NavLink
|
||||
to={item.link}
|
||||
className={styles.link}
|
||||
activeClassName={styles.linkActive}
|
||||
exact
|
||||
>
|
||||
{item.title}
|
||||
</NavLink>
|
||||
)
|
||||
|
||||
export default class Header extends PureComponent {
|
||||
public render() {
|
||||
return (
|
||||
<header className={styles.header}>
|
||||
<div className={styles.headerContent}>
|
||||
<NavLink to="/" className={styles.headerLogo}>
|
||||
<Logo className={styles.headerLogoImage} />
|
||||
<h1 className={styles.headerTitle}>{meta.title}</h1>
|
||||
</NavLink>
|
||||
public render() {
|
||||
return (
|
||||
<header className={styles.header}>
|
||||
<div className={styles.headerContent}>
|
||||
<NavLink to="/" className={styles.headerLogo}>
|
||||
<Logo className={styles.headerLogoImage} />
|
||||
<h1 className={styles.headerTitle}>{meta.title}</h1>
|
||||
</NavLink>
|
||||
|
||||
<nav className={styles.headerMenu}>
|
||||
{menu.map(item => (
|
||||
<MenuItem key={item.title} item={item} />
|
||||
))}
|
||||
<AccountStatus className={styles.accountStatus} />
|
||||
</nav>
|
||||
</div>
|
||||
</header>
|
||||
)
|
||||
}
|
||||
<nav className={styles.headerMenu}>
|
||||
{menu.map(item => (
|
||||
<MenuItem key={item.title} item={item} />
|
||||
))}
|
||||
<AccountStatus className={styles.accountStatus} />
|
||||
</nav>
|
||||
</div>
|
||||
</header>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -9,151 +9,153 @@ import ReactGA from 'react-ga'
|
||||
import cleanupContentType from '../../../utils/cleanupContentType'
|
||||
|
||||
export const messages: any = {
|
||||
99: 'Decrypting file URL...',
|
||||
0: '1/3<br />Asking for agreement signature...',
|
||||
1: '1/3<br />Agreement initialized.',
|
||||
2: '2/3<br />Asking for two payment confirmations...',
|
||||
3: '2/3<br />Payment confirmed. Requesting access...',
|
||||
4: '3/3<br /> Access granted. Consuming file...'
|
||||
99: 'Decrypting file URL...',
|
||||
0: '1/3<br />Asking for agreement signature...',
|
||||
1: '1/3<br />Agreement initialized.',
|
||||
2: '2/3<br />Asking for two payment confirmations...',
|
||||
3: '2/3<br />Payment confirmed. Requesting access...',
|
||||
4: '3/3<br /> Access granted. Consuming file...'
|
||||
}
|
||||
|
||||
interface AssetFileProps {
|
||||
file: File
|
||||
ddo: DDO
|
||||
file: File
|
||||
ddo: DDO
|
||||
}
|
||||
|
||||
interface AssetFileState {
|
||||
isLoading: boolean
|
||||
error: string
|
||||
step: number
|
||||
isLoading: boolean
|
||||
error: string
|
||||
step: number
|
||||
}
|
||||
|
||||
export default class AssetFile extends PureComponent<
|
||||
AssetFileProps,
|
||||
AssetFileState
|
||||
AssetFileProps,
|
||||
AssetFileState
|
||||
> {
|
||||
public static contextType = User
|
||||
public static contextType = User
|
||||
|
||||
public state = {
|
||||
isLoading: false,
|
||||
error: '',
|
||||
step: 99
|
||||
}
|
||||
|
||||
private resetState = () =>
|
||||
this.setState({
|
||||
isLoading: true,
|
||||
error: '',
|
||||
step: 99
|
||||
})
|
||||
|
||||
private purchaseAsset = async (ddo: DDO, index: number) => {
|
||||
this.resetState()
|
||||
|
||||
ReactGA.event({
|
||||
category: 'Purchase',
|
||||
action: 'purchaseAsset-start ' + ddo.id
|
||||
})
|
||||
|
||||
const { ocean } = this.context
|
||||
|
||||
try {
|
||||
const accounts = await ocean.accounts.list()
|
||||
const service = ddo.findServiceByType('access')
|
||||
|
||||
const agreements = await ocean.keeper.conditions.accessSecretStoreCondition.getGrantedDidByConsumer(
|
||||
accounts[0].id
|
||||
)
|
||||
const agreement = agreements.find((element: any) => {
|
||||
return element.did === ddo.id
|
||||
})
|
||||
|
||||
let agreementId
|
||||
|
||||
if (agreement) {
|
||||
;({ agreementId } = agreement)
|
||||
} else {
|
||||
agreementId = await ocean.assets
|
||||
.order(ddo.id, service.index, accounts[0])
|
||||
.next((step: number) => this.setState({ step }))
|
||||
}
|
||||
|
||||
// manually add another step here for better UX
|
||||
this.setState({ step: 4 })
|
||||
|
||||
const path = await ocean.assets.consume(
|
||||
agreementId,
|
||||
ddo.id,
|
||||
service.index,
|
||||
accounts[0],
|
||||
'',
|
||||
index
|
||||
)
|
||||
Logger.log('path', path)
|
||||
ReactGA.event({
|
||||
category: 'Purchase',
|
||||
action: 'purchaseAsset-end ' + ddo.id
|
||||
})
|
||||
this.setState({ isLoading: false })
|
||||
} catch (error) {
|
||||
Logger.error('error', error.message)
|
||||
this.setState({
|
||||
public state = {
|
||||
isLoading: false,
|
||||
error: `${error.message}. Sorry about that, can you try again?`
|
||||
})
|
||||
ReactGA.event({
|
||||
category: 'Purchase',
|
||||
action: 'purchaseAsset-error ' + error.message
|
||||
})
|
||||
error: '',
|
||||
step: 99
|
||||
}
|
||||
}
|
||||
|
||||
public render() {
|
||||
const { ddo, file } = this.props
|
||||
const { isLoading, error, step } = this.state
|
||||
const { isLogged } = this.context
|
||||
const { index, contentType, contentLength } = file
|
||||
private resetState = () =>
|
||||
this.setState({
|
||||
isLoading: true,
|
||||
error: '',
|
||||
step: 99
|
||||
})
|
||||
|
||||
return (
|
||||
<div className={styles.fileWrap}>
|
||||
<ul key={index} className={styles.file}>
|
||||
{contentType || contentLength ? (
|
||||
<>
|
||||
<li>{cleanupContentType(contentType)}</li>
|
||||
<li>
|
||||
{contentLength && contentLength !== '0'
|
||||
? filesize(contentLength)
|
||||
: ''}
|
||||
</li>
|
||||
{/* <li>{encoding}</li> */}
|
||||
{/* <li>{compression}</li> */}
|
||||
</>
|
||||
) : (
|
||||
<li className={styles.empty}>No file info available</li>
|
||||
)}
|
||||
</ul>
|
||||
private purchaseAsset = async (ddo: DDO, index: number) => {
|
||||
this.resetState()
|
||||
|
||||
{isLoading ? (
|
||||
<Spinner message={messages[step]} />
|
||||
) : (
|
||||
<Market.Consumer>
|
||||
{market => (
|
||||
<Button
|
||||
primary
|
||||
className={styles.buttonMain}
|
||||
// weird 0 hack so TypeScript is happy
|
||||
onClick={() => this.purchaseAsset(ddo, index || 0)}
|
||||
disabled={!isLogged || !market.networkMatch}
|
||||
name="Download"
|
||||
>
|
||||
Get file
|
||||
</Button>
|
||||
)}
|
||||
</Market.Consumer>
|
||||
)}
|
||||
ReactGA.event({
|
||||
category: 'Purchase',
|
||||
action: 'purchaseAsset-start ' + ddo.id
|
||||
})
|
||||
|
||||
{error !== '' && <div className={styles.error}>{error}</div>}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
const { ocean } = this.context
|
||||
|
||||
try {
|
||||
const accounts = await ocean.accounts.list()
|
||||
const service = ddo.findServiceByType('access')
|
||||
|
||||
const agreements = await ocean.keeper.conditions.accessSecretStoreCondition.getGrantedDidByConsumer(
|
||||
accounts[0].id
|
||||
)
|
||||
const agreement = agreements.find((element: any) => {
|
||||
return element.did === ddo.id
|
||||
})
|
||||
|
||||
let agreementId
|
||||
|
||||
if (agreement) {
|
||||
;({ agreementId } = agreement)
|
||||
} else {
|
||||
agreementId = await ocean.assets
|
||||
.order(ddo.id, service.index, accounts[0])
|
||||
.next((step: number) => this.setState({ step }))
|
||||
}
|
||||
|
||||
// manually add another step here for better UX
|
||||
this.setState({ step: 4 })
|
||||
|
||||
const path = await ocean.assets.consume(
|
||||
agreementId,
|
||||
ddo.id,
|
||||
service.index,
|
||||
accounts[0],
|
||||
'',
|
||||
index
|
||||
)
|
||||
Logger.log('path', path)
|
||||
ReactGA.event({
|
||||
category: 'Purchase',
|
||||
action: 'purchaseAsset-end ' + ddo.id
|
||||
})
|
||||
this.setState({ isLoading: false })
|
||||
} catch (error) {
|
||||
Logger.error('error', error.message)
|
||||
this.setState({
|
||||
isLoading: false,
|
||||
error: `${error.message}. Sorry about that, can you try again?`
|
||||
})
|
||||
ReactGA.event({
|
||||
category: 'Purchase',
|
||||
action: 'purchaseAsset-error ' + error.message
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
public render() {
|
||||
const { ddo, file } = this.props
|
||||
const { isLoading, error, step } = this.state
|
||||
const { isLogged } = this.context
|
||||
const { index, contentType, contentLength } = file
|
||||
|
||||
return (
|
||||
<div className={styles.fileWrap}>
|
||||
<ul key={index} className={styles.file}>
|
||||
{contentType || contentLength ? (
|
||||
<>
|
||||
<li>{cleanupContentType(contentType)}</li>
|
||||
<li>
|
||||
{contentLength && contentLength !== '0'
|
||||
? filesize(contentLength)
|
||||
: ''}
|
||||
</li>
|
||||
{/* <li>{encoding}</li> */}
|
||||
{/* <li>{compression}</li> */}
|
||||
</>
|
||||
) : (
|
||||
<li className={styles.empty}>No file info available</li>
|
||||
)}
|
||||
</ul>
|
||||
|
||||
{isLoading ? (
|
||||
<Spinner message={messages[step]} />
|
||||
) : (
|
||||
<Market.Consumer>
|
||||
{market => (
|
||||
<Button
|
||||
primary
|
||||
className={styles.buttonMain}
|
||||
// weird 0 hack so TypeScript is happy
|
||||
onClick={() =>
|
||||
this.purchaseAsset(ddo, index || 0)
|
||||
}
|
||||
disabled={!isLogged || !market.networkMatch}
|
||||
name="Download"
|
||||
>
|
||||
Get file
|
||||
</Button>
|
||||
)}
|
||||
</Market.Consumer>
|
||||
)}
|
||||
|
||||
{error !== '' && <div className={styles.error}>{error}</div>}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -27,27 +27,60 @@ export const ipfsNodeUri =
|
||||
//
|
||||
export const CONNECTIONS = {
|
||||
pacific: {
|
||||
nodeUri: 'https://pacific.oceanprotocol.com',
|
||||
aquariusUri: 'https://aquarius.commons.oceanprotocol.com',
|
||||
brizoUri: 'https://brizo.commons.oceanprotocol.com',
|
||||
brizoAddress: '0x008c25ed3594e094db4592f4115d5fa74c4f41ea',
|
||||
secretStoreUri: 'https://secret-store.oceanprotocol.com',
|
||||
faucetUri: 'https://faucet.oceanprotocol.com'
|
||||
nodeUri:
|
||||
process.env.REACT_APP_NODE_URI ||
|
||||
'https://pacific.oceanprotocol.com',
|
||||
aquariusUri:
|
||||
process.env.REACT_APP_AQUARIUS_URI ||
|
||||
'https://aquarius.commons.oceanprotocol.com',
|
||||
brizoUri:
|
||||
process.env.REACT_APP_BRIZO_URI ||
|
||||
'https://brizo.commons.oceanprotocol.com',
|
||||
brizoAddress:
|
||||
process.env.REACT_APP_BRIZO_ADDRESS ||
|
||||
'0x008c25ed3594e094db4592f4115d5fa74c4f41ea',
|
||||
secretStoreUri:
|
||||
process.env.REACT_APP_SECRET_STORE_URI ||
|
||||
'https://secret-store.oceanprotocol.com',
|
||||
faucetUri:
|
||||
process.env.REACT_APP_FAUCET_URI ||
|
||||
'https://faucet.oceanprotocol.com'
|
||||
},
|
||||
nile: {
|
||||
nodeUri: 'https://nile.dev-ocean.com',
|
||||
aquariusUri: 'https://aquarius.nile.dev-ocean.com',
|
||||
brizoUri: 'https://brizo.nile.dev-ocean.com',
|
||||
brizoAddress: '0x4aaab179035dc57b35e2ce066919048686f82972',
|
||||
secretStoreUri: 'https://secret-store.nile.dev-ocean.com',
|
||||
faucetUri: 'https://faucet.nile.dev-ocean.com'
|
||||
nodeUri: process.env.REACT_APP_NODE_URI || 'https://nile.dev-ocean.com',
|
||||
aquariusUri:
|
||||
process.env.REACT_APP_AQUARIUS_URI ||
|
||||
'https://aquarius.nile.dev-ocean.com',
|
||||
brizoUri:
|
||||
process.env.REACT_APP_BRIZO_URI ||
|
||||
'https://brizo.nile.dev-ocean.com',
|
||||
brizoAddress:
|
||||
process.env.REACT_APP_BRIZO_ADDRESS ||
|
||||
'0x4aaab179035dc57b35e2ce066919048686f82972',
|
||||
secretStoreUri:
|
||||
process.env.REACT_APP_SECRET_STORE_URI ||
|
||||
'https://secret-store.nile.dev-ocean.com',
|
||||
faucetUri:
|
||||
process.env.REACT_APP_FAUCET_URI ||
|
||||
'https://faucet.nile.dev-ocean.com'
|
||||
},
|
||||
duero: {
|
||||
nodeUri: 'https://duero.dev-ocean.com',
|
||||
aquariusUri: 'https://aquarius.duero.dev-ocean.com',
|
||||
brizoUri: 'https://brizo.duero.dev-ocean.com',
|
||||
brizoAddress: '0x9d4ed58293f71122ad6a733c1603927a150735d0',
|
||||
secretStoreUri: 'https://secret-store.duero.dev-ocean.com',
|
||||
faucetUri: 'https://faucet.duero.dev-ocean.com'
|
||||
nodeUri:
|
||||
process.env.REACT_APP_NODE_URI || 'https://duero.dev-ocean.com',
|
||||
aquariusUri:
|
||||
process.env.REACT_APP_AQUARIUS_URI ||
|
||||
'https://aquarius.duero.dev-ocean.com',
|
||||
brizoUri:
|
||||
process.env.REACT_APP_BRIZO_URI ||
|
||||
'https://brizo.duero.dev-ocean.com',
|
||||
brizoAddress:
|
||||
process.env.REACT_APP_BRIZO_ADDRESS ||
|
||||
'0x9d4ed58293f71122ad6a733c1603927a150735d0',
|
||||
secretStoreUri:
|
||||
process.env.REACT_APP_SECRET_STORE_URI ||
|
||||
'https://secret-store.duero.dev-ocean.com',
|
||||
faucetUri:
|
||||
process.env.REACT_APP_FAUCET_URI ||
|
||||
'https://faucet.duero.dev-ocean.com'
|
||||
}
|
||||
}
|
||||
|
@ -1,48 +1,48 @@
|
||||
import Web3 from 'web3'
|
||||
|
||||
export class MetamaskProvider {
|
||||
private web3: Web3
|
||||
private web3: Web3
|
||||
|
||||
public constructor() {
|
||||
// Default
|
||||
this.web3 = null as any
|
||||
// Modern dapp browsers
|
||||
if (window.ethereum) {
|
||||
this.web3 = new Web3(window.ethereum)
|
||||
public constructor() {
|
||||
// Default
|
||||
this.web3 = null as any
|
||||
// Modern dapp browsers
|
||||
if (window.ethereum) {
|
||||
this.web3 = new Web3(window.ethereum)
|
||||
}
|
||||
// Legacy dapp browsers
|
||||
else if (window.web3) {
|
||||
this.web3 = new Web3(window.web3.currentProvider)
|
||||
}
|
||||
}
|
||||
// Legacy dapp browsers
|
||||
else if (window.web3) {
|
||||
this.web3 = new Web3(window.web3.currentProvider)
|
||||
|
||||
public async isAvailable() {
|
||||
return this.web3 !== null
|
||||
}
|
||||
}
|
||||
|
||||
public async isAvailable() {
|
||||
return this.web3 !== null
|
||||
}
|
||||
|
||||
public async isLogged() {
|
||||
if (this.web3 === null) return false
|
||||
if ((await this.web3.eth.getAccounts()).length > 0) {
|
||||
return true
|
||||
public async isLogged() {
|
||||
if (this.web3 === null) return false
|
||||
if ((await this.web3.eth.getAccounts()).length > 0) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
public async startLogin() {
|
||||
try {
|
||||
await window.ethereum.enable()
|
||||
localStorage.setItem('logType', 'Metamask')
|
||||
} catch (error) {
|
||||
return false
|
||||
public async startLogin() {
|
||||
try {
|
||||
await window.ethereum.enable()
|
||||
localStorage.setItem('logType', 'Metamask')
|
||||
} catch (error) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async logout() {
|
||||
localStorage.removeItem('logType')
|
||||
// reload page?
|
||||
}
|
||||
public async logout() {
|
||||
localStorage.removeItem('logType')
|
||||
// reload page?
|
||||
}
|
||||
|
||||
public getProvider() {
|
||||
return this.web3
|
||||
}
|
||||
public getProvider() {
|
||||
return this.web3
|
||||
}
|
||||
}
|
||||
|
@ -5,16 +5,16 @@ import App from './App'
|
||||
import * as serviceWorker from './serviceWorker'
|
||||
|
||||
function renderToDOM() {
|
||||
const root = document.getElementById('root')
|
||||
const root = document.getElementById('root')
|
||||
|
||||
if (root !== null) {
|
||||
ReactDOM.render(
|
||||
<UserProvider>
|
||||
<App />
|
||||
</UserProvider>,
|
||||
root
|
||||
)
|
||||
}
|
||||
if (root !== null) {
|
||||
ReactDOM.render(
|
||||
<UserProvider>
|
||||
<App />
|
||||
</UserProvider>,
|
||||
root
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export { renderToDOM }
|
||||
|
@ -1,22 +1,22 @@
|
||||
import { MetaData } from '@oceanprotocol/squid'
|
||||
|
||||
const AssetModel: MetaData = {
|
||||
// OEP-08 Attributes
|
||||
// https://github.com/oceanprotocol/OEPs/tree/master/8
|
||||
main: {
|
||||
type: 'dataset',
|
||||
name: '',
|
||||
dateCreated: '',
|
||||
author: '',
|
||||
license: '',
|
||||
price: '',
|
||||
files: []
|
||||
},
|
||||
additionalInformation: {
|
||||
description: '',
|
||||
copyrightHolder: '',
|
||||
categories: []
|
||||
}
|
||||
// OEP-08 Attributes
|
||||
// https://github.com/oceanprotocol/OEPs/tree/master/8
|
||||
main: {
|
||||
type: 'dataset',
|
||||
name: '',
|
||||
dateCreated: '',
|
||||
author: '',
|
||||
license: '',
|
||||
price: '',
|
||||
files: []
|
||||
},
|
||||
additionalInformation: {
|
||||
description: '',
|
||||
copyrightHolder: '',
|
||||
categories: []
|
||||
}
|
||||
}
|
||||
|
||||
export default AssetModel
|
||||
|
@ -10,48 +10,48 @@ const history = createMemoryHistory()
|
||||
const location = createLocation('/faucet')
|
||||
|
||||
const setup = () => {
|
||||
const utils = render(
|
||||
<User.Provider value={userMockConnected}>
|
||||
<Market.Provider
|
||||
value={{
|
||||
network: 'pacific',
|
||||
totalAssets: 100,
|
||||
categories: [''],
|
||||
networkMatch: true
|
||||
}}
|
||||
>
|
||||
<MemoryRouter>
|
||||
<Faucet
|
||||
history={history}
|
||||
location={location}
|
||||
match={{ params: '', path: '', url: '', isExact: true }}
|
||||
/>
|
||||
</MemoryRouter>
|
||||
</Market.Provider>
|
||||
</User.Provider>
|
||||
)
|
||||
const button = utils.getByText('Request ETH')
|
||||
const { container } = utils
|
||||
return { button, container, ...utils }
|
||||
const utils = render(
|
||||
<User.Provider value={userMockConnected}>
|
||||
<Market.Provider
|
||||
value={{
|
||||
network: 'pacific',
|
||||
totalAssets: 100,
|
||||
categories: [''],
|
||||
networkMatch: true
|
||||
}}
|
||||
>
|
||||
<MemoryRouter>
|
||||
<Faucet
|
||||
history={history}
|
||||
location={location}
|
||||
match={{ params: '', path: '', url: '', isExact: true }}
|
||||
/>
|
||||
</MemoryRouter>
|
||||
</Market.Provider>
|
||||
</User.Provider>
|
||||
)
|
||||
const button = utils.getByText('Request ETH')
|
||||
const { container } = utils
|
||||
return { button, container, ...utils }
|
||||
}
|
||||
|
||||
describe('Faucet', () => {
|
||||
it('renders without crashing', () => {
|
||||
const { container } = setup()
|
||||
expect(container.firstChild).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('shows actions when connected', () => {
|
||||
const { button } = setup()
|
||||
expect(button).toBeInTheDocument()
|
||||
expect(button).not.toHaveAttribute('disabled')
|
||||
})
|
||||
|
||||
it('fires requestFromFaucet', async () => {
|
||||
await act(async () => {
|
||||
const { button } = setup()
|
||||
fireEvent.click(button)
|
||||
it('renders without crashing', () => {
|
||||
const { container } = setup()
|
||||
expect(container.firstChild).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('shows actions when connected', () => {
|
||||
const { button } = setup()
|
||||
expect(button).toBeInTheDocument()
|
||||
expect(button).not.toHaveAttribute('disabled')
|
||||
})
|
||||
|
||||
it('fires requestFromFaucet', async () => {
|
||||
await act(async () => {
|
||||
const { button } = setup()
|
||||
fireEvent.click(button)
|
||||
})
|
||||
expect(userMockConnected.requestFromFaucet).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
expect(userMockConnected.requestFromFaucet).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
})
|
||||
|
@ -1,9 +1,9 @@
|
||||
import React, {
|
||||
lazy,
|
||||
Suspense,
|
||||
FormEvent,
|
||||
PureComponent,
|
||||
ChangeEvent
|
||||
lazy,
|
||||
Suspense,
|
||||
FormEvent,
|
||||
PureComponent,
|
||||
ChangeEvent
|
||||
} from 'react'
|
||||
import axios from 'axios'
|
||||
import { Logger, File } from '@oceanprotocol/squid'
|
||||
@ -21,196 +21,202 @@ import Spinner from '../../../components/atoms/Spinner'
|
||||
const Ipfs = lazy(() => import('./Ipfs'))
|
||||
|
||||
export interface FilePublish extends File {
|
||||
found: boolean // non-standard
|
||||
found: boolean // non-standard
|
||||
}
|
||||
|
||||
interface FilesProps {
|
||||
files: File[]
|
||||
placeholder: string
|
||||
help?: string
|
||||
name: string
|
||||
onChange(
|
||||
event:
|
||||
| ChangeEvent<HTMLInputElement>
|
||||
| FormEvent<HTMLInputElement>
|
||||
| ChangeEvent<HTMLSelectElement>
|
||||
| ChangeEvent<HTMLTextAreaElement>
|
||||
): void
|
||||
files: File[]
|
||||
placeholder: string
|
||||
help?: string
|
||||
name: string
|
||||
onChange(
|
||||
event:
|
||||
| ChangeEvent<HTMLInputElement>
|
||||
| FormEvent<HTMLInputElement>
|
||||
| ChangeEvent<HTMLSelectElement>
|
||||
| ChangeEvent<HTMLTextAreaElement>
|
||||
): void
|
||||
}
|
||||
|
||||
interface FilesStates {
|
||||
isFormShown: boolean
|
||||
isIpfsFormShown: boolean
|
||||
isFormShown: boolean
|
||||
isIpfsFormShown: boolean
|
||||
}
|
||||
|
||||
const buttons = [
|
||||
{
|
||||
id: 'url',
|
||||
title: '+ From URL',
|
||||
titleActive: '- Cancel'
|
||||
},
|
||||
{
|
||||
id: 'ipfs',
|
||||
title: '+ Add to IPFS',
|
||||
titleActive: '- Cancel'
|
||||
}
|
||||
{
|
||||
id: 'url',
|
||||
title: '+ From URL',
|
||||
titleActive: '- Cancel'
|
||||
},
|
||||
{
|
||||
id: 'ipfs',
|
||||
title: '+ Add to IPFS',
|
||||
titleActive: '- Cancel'
|
||||
}
|
||||
]
|
||||
|
||||
export default class Files extends PureComponent<FilesProps, FilesStates> {
|
||||
public state: FilesStates = {
|
||||
isFormShown: false,
|
||||
isIpfsFormShown: false
|
||||
}
|
||||
|
||||
// for canceling axios requests
|
||||
public signal = axios.CancelToken.source()
|
||||
|
||||
public componentWillUnmount() {
|
||||
this.signal.cancel()
|
||||
}
|
||||
|
||||
private toggleForm = (e: Event, form: string) => {
|
||||
e.preventDefault()
|
||||
|
||||
this.setState({
|
||||
isFormShown: form === 'url' ? !this.state.isFormShown : false,
|
||||
isIpfsFormShown: form === 'ipfs' ? !this.state.isIpfsFormShown : false
|
||||
})
|
||||
}
|
||||
|
||||
private async getFile(url: string) {
|
||||
const file: FilePublish = {
|
||||
url,
|
||||
contentType: '',
|
||||
found: false // non-standard
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await axios({
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
url: `${serviceUri}/api/v1/urlcheck`,
|
||||
data: { url },
|
||||
cancelToken: this.signal.token
|
||||
})
|
||||
|
||||
const { contentLength, contentType, found } = response.data.result
|
||||
|
||||
if (contentLength) file.contentLength = contentLength
|
||||
if (contentType) {
|
||||
file.contentType = contentType
|
||||
file.compression = cleanupContentType(contentType)
|
||||
}
|
||||
|
||||
file.found = found
|
||||
|
||||
return file
|
||||
} catch (error) {
|
||||
!axios.isCancel(error) && Logger.error(error.message)
|
||||
}
|
||||
}
|
||||
|
||||
private addFile = async (url: string) => {
|
||||
// check for duplicate urls
|
||||
const duplicateFiles = this.props.files.filter(props =>
|
||||
url.includes(props.url)
|
||||
)
|
||||
|
||||
if (duplicateFiles.length > 0) {
|
||||
return this.setState({
|
||||
public state: FilesStates = {
|
||||
isFormShown: false,
|
||||
isIpfsFormShown: false
|
||||
})
|
||||
}
|
||||
|
||||
const file: FilePublish | undefined = await this.getFile(url)
|
||||
file && this.props.files.push(file)
|
||||
// for canceling axios requests
|
||||
public signal = axios.CancelToken.source()
|
||||
|
||||
const event = {
|
||||
currentTarget: {
|
||||
name: 'files',
|
||||
value: this.props.files
|
||||
}
|
||||
public componentWillUnmount() {
|
||||
this.signal.cancel()
|
||||
}
|
||||
this.props.onChange(event as any)
|
||||
|
||||
this.setState({
|
||||
isFormShown: false,
|
||||
isIpfsFormShown: false
|
||||
})
|
||||
private toggleForm = (e: Event, form: string) => {
|
||||
e.preventDefault()
|
||||
|
||||
this.forceUpdate()
|
||||
}
|
||||
|
||||
private removeFile = (index: number) => {
|
||||
this.props.files.splice(index, 1)
|
||||
const event = {
|
||||
currentTarget: {
|
||||
name: 'files',
|
||||
value: this.props.files
|
||||
}
|
||||
this.setState({
|
||||
isFormShown: form === 'url' ? !this.state.isFormShown : false,
|
||||
isIpfsFormShown:
|
||||
form === 'ipfs' ? !this.state.isIpfsFormShown : false
|
||||
})
|
||||
}
|
||||
this.props.onChange(event as any)
|
||||
this.forceUpdate()
|
||||
}
|
||||
|
||||
public render() {
|
||||
const { files, help, placeholder, name, onChange } = this.props
|
||||
const { isFormShown, isIpfsFormShown } = this.state
|
||||
private async getFile(url: string) {
|
||||
const file: FilePublish = {
|
||||
url,
|
||||
contentType: '',
|
||||
found: false // non-standard
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{help && <Help>{help}</Help>}
|
||||
try {
|
||||
const response = await axios({
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
url: `${serviceUri}/api/v1/urlcheck`,
|
||||
data: { url },
|
||||
cancelToken: this.signal.token
|
||||
})
|
||||
|
||||
{/* Use hidden input to collect files */}
|
||||
<input
|
||||
type="hidden"
|
||||
name={name}
|
||||
value={JSON.stringify(files)}
|
||||
onChange={onChange}
|
||||
data-testid="files"
|
||||
/>
|
||||
const { contentLength, contentType, found } = response.data.result
|
||||
|
||||
<div className={styles.newItems}>
|
||||
{files.length > 0 && (
|
||||
<ul className={styles.itemsList}>
|
||||
{files.map((item: any, index: number) => (
|
||||
<Item
|
||||
key={shortid.generate()}
|
||||
item={item}
|
||||
removeFile={() => this.removeFile(index)}
|
||||
if (contentLength) file.contentLength = contentLength
|
||||
if (contentType) {
|
||||
file.contentType = contentType
|
||||
file.compression = cleanupContentType(contentType)
|
||||
}
|
||||
|
||||
file.found = found
|
||||
|
||||
return file
|
||||
} catch (error) {
|
||||
!axios.isCancel(error) && Logger.error(error.message)
|
||||
}
|
||||
}
|
||||
|
||||
private addFile = async (url: string) => {
|
||||
// check for duplicate urls
|
||||
const duplicateFiles = this.props.files.filter(props =>
|
||||
url.includes(props.url)
|
||||
)
|
||||
|
||||
if (duplicateFiles.length > 0) {
|
||||
return this.setState({
|
||||
isFormShown: false,
|
||||
isIpfsFormShown: false
|
||||
})
|
||||
}
|
||||
|
||||
const file: FilePublish | undefined = await this.getFile(url)
|
||||
file && this.props.files.push(file)
|
||||
|
||||
const event = {
|
||||
currentTarget: {
|
||||
name: 'files',
|
||||
value: this.props.files
|
||||
}
|
||||
}
|
||||
this.props.onChange(event as any)
|
||||
|
||||
this.setState({
|
||||
isFormShown: false,
|
||||
isIpfsFormShown: false
|
||||
})
|
||||
|
||||
this.forceUpdate()
|
||||
}
|
||||
|
||||
private removeFile = (index: number) => {
|
||||
this.props.files.splice(index, 1)
|
||||
const event = {
|
||||
currentTarget: {
|
||||
name: 'files',
|
||||
value: this.props.files
|
||||
}
|
||||
}
|
||||
this.props.onChange(event as any)
|
||||
this.forceUpdate()
|
||||
}
|
||||
|
||||
public render() {
|
||||
const { files, help, placeholder, name, onChange } = this.props
|
||||
const { isFormShown, isIpfsFormShown } = this.state
|
||||
|
||||
return (
|
||||
<>
|
||||
{help && <Help>{help}</Help>}
|
||||
|
||||
{/* Use hidden input to collect files */}
|
||||
<input
|
||||
type="hidden"
|
||||
name={name}
|
||||
value={JSON.stringify(files)}
|
||||
onChange={onChange}
|
||||
data-testid="files"
|
||||
/>
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
|
||||
{buttons.map(button => {
|
||||
const isActive =
|
||||
(button.id === 'url' && isFormShown) ||
|
||||
(button.id === 'ipfs' && isIpfsFormShown)
|
||||
<div className={styles.newItems}>
|
||||
{files.length > 0 && (
|
||||
<ul className={styles.itemsList}>
|
||||
{files.map((item: any, index: number) => (
|
||||
<Item
|
||||
key={shortid.generate()}
|
||||
item={item}
|
||||
removeFile={() => this.removeFile(index)}
|
||||
/>
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
|
||||
return (
|
||||
<Button
|
||||
key={shortid.generate()}
|
||||
link
|
||||
onClick={(e: Event) => this.toggleForm(e, button.id)}
|
||||
>
|
||||
{isActive ? button.titleActive : button.title}
|
||||
</Button>
|
||||
)
|
||||
})}
|
||||
{buttons.map(button => {
|
||||
const isActive =
|
||||
(button.id === 'url' && isFormShown) ||
|
||||
(button.id === 'ipfs' && isIpfsFormShown)
|
||||
|
||||
{isFormShown && (
|
||||
<ItemForm placeholder={placeholder} addFile={this.addFile} />
|
||||
)}
|
||||
return (
|
||||
<Button
|
||||
key={shortid.generate()}
|
||||
link
|
||||
onClick={(e: Event) =>
|
||||
this.toggleForm(e, button.id)
|
||||
}
|
||||
>
|
||||
{isActive ? button.titleActive : button.title}
|
||||
</Button>
|
||||
)
|
||||
})}
|
||||
|
||||
{isIpfsFormShown && (
|
||||
<Suspense fallback={<Spinner message="Loading..." />}>
|
||||
<Ipfs addFile={this.addFile} />
|
||||
</Suspense>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
{isFormShown && (
|
||||
<ItemForm
|
||||
placeholder={placeholder}
|
||||
addFile={this.addFile}
|
||||
/>
|
||||
)}
|
||||
|
||||
{isIpfsFormShown && (
|
||||
<Suspense fallback={<Spinner message="Loading..." />}>
|
||||
<Ipfs addFile={this.addFile} />
|
||||
</Suspense>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user