mirror of
https://github.com/oceanprotocol/commons.git
synced 2023-03-15 18:03:00 +01:00
cleanup and more fine-grained bootstrap process
* new detection flow, one after the other: web3 -> network -> ocean -> accounts * make account enabling part of bootstrap * kick out dedicated startLogin action * plan for modern, legacy, and non-dapp browsers * consolidate fetchNetwork & fetchAccounts
This commit is contained in:
parent
fe695009ff
commit
3a8d6ea284
|
@ -43,45 +43,31 @@ interface AppState {
|
||||||
network: string
|
network: string
|
||||||
web3: Web3
|
web3: Web3
|
||||||
ocean: any
|
ocean: any
|
||||||
startLogin: () => void
|
requestFromFaucet(): void
|
||||||
message: string
|
message: string
|
||||||
}
|
}
|
||||||
|
|
||||||
class App extends Component<{}, AppState> {
|
class App extends Component<{}, AppState> {
|
||||||
private accountsInterval: any
|
private accountsInterval: any = null
|
||||||
private networkInterval: any
|
private networkInterval: any = null
|
||||||
|
|
||||||
public startLogin = (event?: any) => {
|
|
||||||
if (event) {
|
|
||||||
event.preventDefault()
|
|
||||||
}
|
|
||||||
this.startLoginProcess()
|
|
||||||
}
|
|
||||||
|
|
||||||
private requestFromFaucet = async () => {
|
private requestFromFaucet = async () => {
|
||||||
if (this.state.account !== '') {
|
try {
|
||||||
try {
|
const url = `${faucetScheme}://${faucetHost}:${faucetPort}/faucet`
|
||||||
const response = await fetch(
|
const response = await fetch(url, {
|
||||||
`${faucetScheme}://${faucetHost}:${faucetPort}/faucet`,
|
method: 'POST',
|
||||||
{
|
headers: {
|
||||||
method: 'POST',
|
Accept: 'application/json',
|
||||||
headers: {
|
'Content-Type': 'application/json'
|
||||||
Accept: 'application/json',
|
},
|
||||||
'Content-Type': 'application/json'
|
body: JSON.stringify({
|
||||||
},
|
address: this.state.account,
|
||||||
body: JSON.stringify({
|
agent: 'commons'
|
||||||
address: this.state.account,
|
})
|
||||||
agent: 'commons'
|
})
|
||||||
})
|
return response.json()
|
||||||
}
|
} catch (error) {
|
||||||
)
|
Logger.log('requestFromFaucet', error)
|
||||||
|
|
||||||
return response.json()
|
|
||||||
} catch (error) {
|
|
||||||
Logger.log('requestFromFaucet', error)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// no account found
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,7 +88,6 @@ class App extends Component<{}, AppState> {
|
||||||
),
|
),
|
||||||
account: '',
|
account: '',
|
||||||
ocean: {} as any,
|
ocean: {} as any,
|
||||||
startLogin: this.startLogin,
|
|
||||||
requestFromFaucet: this.requestFromFaucet,
|
requestFromFaucet: this.requestFromFaucet,
|
||||||
message: 'Connecting to Ocean...'
|
message: 'Connecting to Ocean...'
|
||||||
}
|
}
|
||||||
|
@ -116,68 +101,72 @@ class App extends Component<{}, AppState> {
|
||||||
|
|
||||||
private bootstrap = async () => {
|
private bootstrap = async () => {
|
||||||
try {
|
try {
|
||||||
if (window.web3) {
|
//
|
||||||
let web3provider = new Web3(window.web3.currentProvider)
|
// Start with Web3 detection
|
||||||
this.setState({
|
//
|
||||||
isWeb3: true,
|
this.setState({ message: 'Setting up Web3...' })
|
||||||
message: 'Setting up Web3...'
|
|
||||||
})
|
|
||||||
|
|
||||||
|
// Modern dapp browsers
|
||||||
|
if (window.ethereum) {
|
||||||
|
window.web3 = new Web3(window.ethereum)
|
||||||
|
this.setState({ isWeb3: true })
|
||||||
|
}
|
||||||
|
// Legacy dapp browsers
|
||||||
|
else if (window.web3) {
|
||||||
|
window.web3 = new Web3(window.web3.currentProvider)
|
||||||
|
this.setState({ isWeb3: true })
|
||||||
|
}
|
||||||
|
// Non-dapp browsers
|
||||||
|
else {
|
||||||
|
this.setState({ isWeb3: false })
|
||||||
|
}
|
||||||
|
|
||||||
|
// Modern & legacy dapp browsers
|
||||||
|
if (this.state.isWeb3) {
|
||||||
//
|
//
|
||||||
// Detecting network with window.web3
|
// Detecting network with window.web3
|
||||||
//
|
//
|
||||||
let isNile
|
let isNile
|
||||||
|
|
||||||
await web3provider.eth.net.getId((err, netId) => {
|
await window.web3.eth.net.getId((err, netId) => {
|
||||||
if (err) return
|
if (err) return
|
||||||
|
|
||||||
isNile = netId === 8995
|
isNile = netId === 8995
|
||||||
const network = isNile ? 'Nile' : netId.toString()
|
const network = isNile ? 'Nile' : netId.toString()
|
||||||
this.setState({ isNile, network })
|
|
||||||
|
if (
|
||||||
|
isNile !== this.state.isNile ||
|
||||||
|
network !== this.state.network
|
||||||
|
) {
|
||||||
|
this.setState({ isNile, network })
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
if (!isNile) {
|
if (!isNile) {
|
||||||
web3provider = this.state.web3
|
window.web3 = this.state.web3
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Provide the Ocean
|
// Provide the Ocean
|
||||||
//
|
//
|
||||||
this.setState({ message: 'Connecting to Ocean...' })
|
this.setState({ message: 'Connecting to Ocean...' })
|
||||||
const { ocean } = await provideOcean(web3provider)
|
|
||||||
|
const { ocean } = await provideOcean(window.web3)
|
||||||
this.setState({ ocean, isLoading: false })
|
this.setState({ ocean, isLoading: false })
|
||||||
|
|
||||||
// Set proper network names now that we have Ocean
|
// Set proper network names now that we have Ocean
|
||||||
const network = await ocean.keeper.getNetworkName()
|
this.fetchNetwork()
|
||||||
isNile = network === 'Nile'
|
|
||||||
this.setState({ isNile, network })
|
|
||||||
|
|
||||||
// Get accounts with Ocean
|
// Get accounts
|
||||||
const accounts = await ocean.accounts.list()
|
this.fetchAccounts()
|
||||||
|
}
|
||||||
if (accounts.length > 0) {
|
// Non-dapp browsers
|
||||||
this.setState({
|
else {
|
||||||
isLogged: true,
|
this.setState({ message: 'Connecting to Ocean...' })
|
||||||
account: accounts[0].getId()
|
|
||||||
})
|
|
||||||
|
|
||||||
const balance = await accounts[0].getBalance()
|
|
||||||
this.setState({ balance })
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
//
|
|
||||||
// No Web3 browser
|
|
||||||
//
|
|
||||||
const { ocean } = await provideOcean(this.state.web3)
|
const { ocean } = await provideOcean(this.state.web3)
|
||||||
this.setState({ isLoading: false })
|
this.setState({ ocean, isLoading: false })
|
||||||
|
|
||||||
const network = await ocean.keeper.getNetworkName()
|
this.fetchNetwork()
|
||||||
const isNile = network === 'Nile'
|
|
||||||
this.setState({
|
|
||||||
isNile,
|
|
||||||
ocean,
|
|
||||||
network
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// error in bootstrap process
|
// error in bootstrap process
|
||||||
|
@ -188,7 +177,7 @@ class App extends Component<{}, AppState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private initAccountsPoll() {
|
private initAccountsPoll() {
|
||||||
if (!this.accountsInterval && this.state.ocean.length) {
|
if (!this.accountsInterval) {
|
||||||
this.accountsInterval = setInterval(
|
this.accountsInterval = setInterval(
|
||||||
this.fetchAccounts,
|
this.fetchAccounts,
|
||||||
POLL_ACCOUNTS
|
POLL_ACCOUNTS
|
||||||
|
@ -197,16 +186,28 @@ class App extends Component<{}, AppState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private initNetworkPoll() {
|
private initNetworkPoll() {
|
||||||
if (!this.networkInterval && this.state.ocean.length) {
|
if (!this.networkInterval) {
|
||||||
this.networkInterval = setInterval(this.fetchNetwork, POLL_NETWORK)
|
this.networkInterval = setInterval(this.fetchNetwork, POLL_NETWORK)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fetchAccounts = async () => {
|
private fetchAccounts = async () => {
|
||||||
const { web3 } = window
|
const { ocean, isWeb3, isLogged, isNile } = this.state
|
||||||
const { ocean } = this.state
|
|
||||||
|
if (isWeb3) {
|
||||||
|
// Modern dapp browsers
|
||||||
|
if (window.ethereum) {
|
||||||
|
if (!isLogged && isNile) {
|
||||||
|
try {
|
||||||
|
await window.ethereum.enable()
|
||||||
|
} catch (error) {
|
||||||
|
// User denied account access...
|
||||||
|
this.accountsInterval = null
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (web3) {
|
|
||||||
const accounts = await ocean.accounts.list()
|
const accounts = await ocean.accounts.list()
|
||||||
|
|
||||||
if (accounts.length > 0) {
|
if (accounts.length > 0) {
|
||||||
|
@ -225,23 +226,16 @@ class App extends Component<{}, AppState> {
|
||||||
this.setState({ balance })
|
this.setState({ balance })
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.state.isLogged !== false &&
|
isLogged !== false &&
|
||||||
this.setState({ isLogged: false, account: '' })
|
this.setState({ isLogged: false, account: '' })
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
this.state.isWeb3 !== false &&
|
|
||||||
this.setState({
|
|
||||||
isWeb3: false,
|
|
||||||
isLogged: false
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fetchNetwork = async () => {
|
private fetchNetwork = async () => {
|
||||||
const { web3 } = window
|
const { ocean, isWeb3 } = this.state
|
||||||
const { ocean } = this.state
|
|
||||||
|
|
||||||
if (web3) {
|
if (isWeb3) {
|
||||||
const network = await ocean.keeper.getNetworkName()
|
const network = await ocean.keeper.getNetworkName()
|
||||||
const isNile = network === 'Nile'
|
const isNile = network === 'Nile'
|
||||||
|
|
||||||
|
@ -249,32 +243,6 @@ class App extends Component<{}, AppState> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private startLoginProcess = async () => {
|
|
||||||
try {
|
|
||||||
if (this.state.isWeb3 && window.ethereum) {
|
|
||||||
await window.ethereum.enable()
|
|
||||||
const accounts = await this.state.ocean.accounts.list()
|
|
||||||
if (accounts.length > 0) {
|
|
||||||
const balance = await accounts[0].getBalance()
|
|
||||||
this.setState({
|
|
||||||
isLogged: true,
|
|
||||||
balance,
|
|
||||||
account: accounts[0].getId()
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
// not unlocked
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// no metamask/mist, show installation guide!
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
Logger.log('error logging', e)
|
|
||||||
// error in logging process
|
|
||||||
// show error
|
|
||||||
// rerun bootstrap process?
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
return (
|
return (
|
||||||
<div className={styles.app}>
|
<div className={styles.app}>
|
||||||
|
|
|
@ -4,7 +4,6 @@ import { Logger } from '@oceanprotocol/squid'
|
||||||
import { User } from '../../context/User'
|
import { User } from '../../context/User'
|
||||||
import Spinner from '../atoms/Spinner'
|
import Spinner from '../atoms/Spinner'
|
||||||
import Asset from '../molecules/Asset'
|
import Asset from '../molecules/Asset'
|
||||||
import Web3message from './Web3message'
|
|
||||||
import styles from './AssetsUser.module.scss'
|
import styles from './AssetsUser.module.scss'
|
||||||
|
|
||||||
export default class AssetsUser extends PureComponent<
|
export default class AssetsUser extends PureComponent<
|
||||||
|
@ -60,48 +59,49 @@ export default class AssetsUser extends PureComponent<
|
||||||
public render() {
|
public render() {
|
||||||
const { account, isNile } = this.context
|
const { account, isNile } = this.context
|
||||||
|
|
||||||
return isNile && account ? (
|
return (
|
||||||
<div className={styles.assetsUser}>
|
isNile &&
|
||||||
{this.props.recent && (
|
account && (
|
||||||
<h2 className={styles.subTitle}>
|
<div className={styles.assetsUser}>
|
||||||
Your Latest Published Data Sets
|
{this.props.recent && (
|
||||||
</h2>
|
<h2 className={styles.subTitle}>
|
||||||
)}
|
Your Latest Published Data Sets
|
||||||
|
</h2>
|
||||||
|
)}
|
||||||
|
|
||||||
{this.state.isLoading ? (
|
{this.state.isLoading ? (
|
||||||
<Spinner />
|
<Spinner />
|
||||||
) : this.state.results.length ? (
|
) : this.state.results.length ? (
|
||||||
<>
|
<>
|
||||||
{this.state.results
|
{this.state.results
|
||||||
.slice(
|
.slice(
|
||||||
0,
|
0,
|
||||||
this.props.recent
|
this.props.recent
|
||||||
? this.props.recent
|
? this.props.recent
|
||||||
: undefined
|
: undefined
|
||||||
)
|
)
|
||||||
.filter(asset => !!asset)
|
.filter(asset => !!asset)
|
||||||
.map((asset: any) => (
|
.map((asset: any) => (
|
||||||
<Asset
|
<Asset
|
||||||
list={this.props.list}
|
list={this.props.list}
|
||||||
key={asset.id}
|
key={asset.id}
|
||||||
asset={asset}
|
asset={asset}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
{this.props.recent && (
|
{this.props.recent && (
|
||||||
<Link className={styles.link} to={'/history'}>
|
<Link className={styles.link} to={'/history'}>
|
||||||
All Data Sets
|
All Data Sets
|
||||||
</Link>
|
</Link>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<div className={styles.empty}>
|
<div className={styles.empty}>
|
||||||
<p>No Data Sets Yet.</p>
|
<p>No Data Sets Yet.</p>
|
||||||
<Link to="/publish">+ Publish A Data Set</Link>
|
<Link to="/publish">+ Publish A Data Set</Link>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
) : (
|
)
|
||||||
<Web3message />
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ export default class Web3message extends PureComponent {
|
||||||
private noWeb3 = () => (
|
private noWeb3 = () => (
|
||||||
<div className={styles.message}>
|
<div className={styles.message}>
|
||||||
<AccountStatus className={styles.status} /> Not a Web3 Browser. For
|
<AccountStatus className={styles.status} /> Not a Web3 Browser. For
|
||||||
publishing or downloading an asset you need to{' '}
|
publishing and downloading an asset you need to{' '}
|
||||||
<a
|
<a
|
||||||
href="https://docs.oceanprotocol.com/tutorials/metamask-setup/"
|
href="https://docs.oceanprotocol.com/tutorials/metamask-setup/"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
|
@ -21,14 +21,11 @@ export default class Web3message extends PureComponent {
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
||||||
private unlockAccount = (states: any) => (
|
private unlockAccount = () => (
|
||||||
<div className={styles.message}>
|
<div className={styles.message}>
|
||||||
<AccountStatus className={styles.status} /> Account locked. For
|
<AccountStatus className={styles.status} /> No accounts detected.
|
||||||
publishing and downloading an asset you need to unlock your Web3
|
For publishing and downloading an asset you need to unlock your Web3
|
||||||
account.{' '}
|
account.
|
||||||
<Button link onClick={states.startLogin}>
|
|
||||||
Unlock account
|
|
||||||
</Button>
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -52,20 +49,18 @@ export default class Web3message extends PureComponent {
|
||||||
)
|
)
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
return (
|
const { isWeb3, isNile, isLogged, network, account } = this.context
|
||||||
<User.Consumer>
|
|
||||||
{states =>
|
return !isWeb3
|
||||||
!states.isWeb3
|
? this.noWeb3()
|
||||||
? this.noWeb3()
|
: !isNile
|
||||||
: !states.isNile
|
? this.wrongNetwork(network)
|
||||||
? this.wrongNetwork(states.network)
|
: !isLogged
|
||||||
: !states.isLogged
|
? this.unlockAccount()
|
||||||
? this.unlockAccount(states)
|
: isLogged
|
||||||
: states.isLogged
|
? this.haveAccount(account)
|
||||||
? this.haveAccount(states.account)
|
: null
|
||||||
: null
|
|
||||||
}
|
|
||||||
</User.Consumer>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Web3message.contextType = User
|
||||||
|
|
|
@ -13,9 +13,6 @@ export const User = React.createContext({
|
||||||
ocn: 0
|
ocn: 0
|
||||||
},
|
},
|
||||||
network: '',
|
network: '',
|
||||||
startLogin: () => {
|
|
||||||
/* empty */
|
|
||||||
},
|
|
||||||
requestFromFaucet: () => {
|
requestFromFaucet: () => {
|
||||||
/* empty */
|
/* empty */
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,7 +76,7 @@ export default class AssetFile extends PureComponent<
|
||||||
public render() {
|
public render() {
|
||||||
const { ddo, file } = this.props
|
const { ddo, file } = this.props
|
||||||
const { isLoading, message, error } = this.state
|
const { isLoading, message, error } = this.state
|
||||||
const { isLogged } = this.context
|
const { isLogged, isNile } = this.context
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.fileWrap}>
|
<div className={styles.fileWrap}>
|
||||||
|
@ -98,7 +98,7 @@ export default class AssetFile extends PureComponent<
|
||||||
primary
|
primary
|
||||||
className={styles.buttonMain}
|
className={styles.buttonMain}
|
||||||
onClick={() => this.purchaseAsset(ddo, file.index)}
|
onClick={() => this.purchaseAsset(ddo, file.index)}
|
||||||
disabled={!isLogged}
|
disabled={!isLogged || !isNile}
|
||||||
>
|
>
|
||||||
Get file
|
Get file
|
||||||
</Button>
|
</Button>
|
||||||
|
|
|
@ -77,7 +77,7 @@ export default class Faucet extends PureComponent<{}, FaucetState> {
|
||||||
<Button
|
<Button
|
||||||
primary
|
primary
|
||||||
onClick={() => this.getTokens(this.context.requestFromFaucet)}
|
onClick={() => this.getTokens(this.context.requestFromFaucet)}
|
||||||
disabled={!this.context.isLogged}
|
disabled={!this.context.isLogged || !this.context.isNile}
|
||||||
>
|
>
|
||||||
Request Ether
|
Request Ether
|
||||||
</Button>
|
</Button>
|
||||||
|
|
|
@ -1,13 +1,21 @@
|
||||||
import React, { Component } from 'react'
|
import React, { Component } from 'react'
|
||||||
import Route from '../components/templates/Route'
|
import Route from '../components/templates/Route'
|
||||||
import AssetsUser from '../components/organisms/AssetsUser'
|
import AssetsUser from '../components/organisms/AssetsUser'
|
||||||
|
import Web3message from '../components/organisms/Web3message'
|
||||||
|
import { User } from '../context/User'
|
||||||
|
|
||||||
export default class History extends Component {
|
export default class History extends Component {
|
||||||
public render() {
|
public render() {
|
||||||
return (
|
return (
|
||||||
<Route title="History">
|
<Route title="History">
|
||||||
|
{(!this.context.isLogged || !this.context.isNile) && (
|
||||||
|
<Web3message />
|
||||||
|
)}
|
||||||
|
|
||||||
<AssetsUser list />
|
<AssetsUser list />
|
||||||
</Route>
|
</Route>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
History.contextType = User
|
||||||
|
|
|
@ -154,29 +154,9 @@ export default class Step extends PureComponent<StepProps, {}> {
|
||||||
{this.nextButton()}
|
{this.nextButton()}
|
||||||
|
|
||||||
{lastStep && (
|
{lastStep && (
|
||||||
<User.Consumer>
|
<Button disabled={!this.context.isLogged} primary>
|
||||||
{states =>
|
Register asset
|
||||||
states.isLogged ? (
|
</Button>
|
||||||
<Button primary>Register asset</Button>
|
|
||||||
) : states.isWeb3 ? (
|
|
||||||
<Button onClick={states.startLogin}>
|
|
||||||
Register asset (unlock Metamask)
|
|
||||||
</Button>
|
|
||||||
) : (
|
|
||||||
<Button
|
|
||||||
onClick={(e: Event) => {
|
|
||||||
e.preventDefault()
|
|
||||||
window.open(
|
|
||||||
'https://docs.oceanprotocol.com/tutorials/metamask-setup/',
|
|
||||||
'_blank'
|
|
||||||
)
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Register asset (install Metamask)
|
|
||||||
</Button>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
</User.Consumer>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -4,6 +4,7 @@ import Route from '../../components/templates/Route'
|
||||||
import Form from '../../components/atoms/Form/Form'
|
import Form from '../../components/atoms/Form/Form'
|
||||||
import AssetModel from '../../models/AssetModel'
|
import AssetModel from '../../models/AssetModel'
|
||||||
import { User } from '../../context/User'
|
import { User } from '../../context/User'
|
||||||
|
import Web3message from '../../components/organisms/Web3message'
|
||||||
import Step from './Step'
|
import Step from './Step'
|
||||||
import Progress from './Progress'
|
import Progress from './Progress'
|
||||||
import ReactGA from 'react-ga'
|
import ReactGA from 'react-ga'
|
||||||
|
@ -318,6 +319,10 @@ class Publish extends Component<{}, PublishState> {
|
||||||
title="Publish"
|
title="Publish"
|
||||||
description="Publish a new data set into the Ocean Protocol Network."
|
description="Publish a new data set into the Ocean Protocol Network."
|
||||||
>
|
>
|
||||||
|
{(!this.context.isLogged || !this.context.isNile) && (
|
||||||
|
<Web3message />
|
||||||
|
)}
|
||||||
|
|
||||||
<Progress steps={steps} currentStep={this.state.currentStep} />
|
<Progress steps={steps} currentStep={this.state.currentStep} />
|
||||||
|
|
||||||
<Form onSubmit={this.registerAsset}>
|
<Form onSubmit={this.registerAsset}>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user