mirror of
https://github.com/oceanprotocol/commons.git
synced 2023-03-15 18:03:00 +01:00
Merge branch 'master' into feature/search-tweaks
This commit is contained in:
commit
0c38b6caa3
1
.dockerignore
Normal file
1
.dockerignore
Normal file
@ -0,0 +1 @@
|
|||||||
|
node_modules
|
14
README.md
14
README.md
@ -29,7 +29,12 @@ If you're a developer and want to contribute to, or want to utilize this marketp
|
|||||||
|
|
||||||
## Get Started
|
## Get Started
|
||||||
|
|
||||||
To make use of all the functionality, you need to connect to the Ocean network. By default, the client will connect to Ocean's Nile test network remotely.
|
To make use of all the functionality, you need to connect to the Ocean network. By default, the client will connect to [Ocean's Nile test network](https://docs.oceanprotocol.com/concepts/testnets/#the-nile-testnet) remotely.
|
||||||
|
|
||||||
|
This repo contains a client and a server, both written in TypeScript:
|
||||||
|
|
||||||
|
- **client**: React app setup with [squid-js](https://github.com/oceanprotocol/squid-js), bootstrapped with [Create React App](https://github.com/facebook/create-react-app)
|
||||||
|
- **server**: Node.js app, utilizing [Express](https://expressjs.com). The server provides various microservices, like remote file checking.
|
||||||
|
|
||||||
To spin up both, the client and the server in a watch mode for local development, execute:
|
To spin up both, the client and the server in a watch mode for local development, execute:
|
||||||
|
|
||||||
@ -58,7 +63,7 @@ Modify `./client/src/config.ts` to use those local connections.
|
|||||||
|
|
||||||
## Production
|
## Production
|
||||||
|
|
||||||
To create a production build of both, the client and the server:
|
To create a production build of both, the client and the server, run from the root of the project:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm run build
|
npm run build
|
||||||
@ -72,12 +77,11 @@ Builds the client for production to the `./client/build` folder, and the server
|
|||||||
npm test
|
npm test
|
||||||
```
|
```
|
||||||
|
|
||||||
Launches the test runner in the interactive watch mode.<br>
|
Launches the test runner in the interactive watch mode.
|
||||||
See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
|
|
||||||
|
|
||||||
## Code Style
|
## Code Style
|
||||||
|
|
||||||
For linting and auto-formatting you can use:
|
For linting and auto-formatting you can use from the root of the project:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# auto format all ts & css with eslint & stylelint
|
# auto format all ts & css with eslint & stylelint
|
||||||
|
1
client/.dockerignore
Normal file
1
client/.dockerignore
Normal file
@ -0,0 +1 @@
|
|||||||
|
node_modules
|
47
client/Dockerfile
Normal file
47
client/Dockerfile
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
FROM node:11-alpine
|
||||||
|
LABEL maintainer="Ocean Protocol <devops@oceanprotocol.com>"
|
||||||
|
|
||||||
|
RUN apk add --no-cache --update\
|
||||||
|
bash\
|
||||||
|
g++\
|
||||||
|
gcc\
|
||||||
|
git\
|
||||||
|
gettext\
|
||||||
|
make\
|
||||||
|
python
|
||||||
|
|
||||||
|
COPY . /app/frontend
|
||||||
|
WORKDIR /app/frontend
|
||||||
|
|
||||||
|
RUN npm install -g npm serve
|
||||||
|
RUN npm install
|
||||||
|
|
||||||
|
# Default ENV values
|
||||||
|
# src/config/config.ts
|
||||||
|
ENV SERVICE_SCHEME='http'
|
||||||
|
ENV SERVICE_HOST='localhost'
|
||||||
|
ENV SERVICE_PORT='4000'
|
||||||
|
ENV NODE_SCHEME='http'
|
||||||
|
ENV NODE_HOST='localhost'
|
||||||
|
ENV NODE_PORT='8545'
|
||||||
|
ENV AQUARIUS_SCHEME='http'
|
||||||
|
ENV AQUARIUS_HOST='localhost'
|
||||||
|
ENV AQUARIUS_PORT='5000'
|
||||||
|
ENV BRIZO_SCHEME='http'
|
||||||
|
ENV BRIZO_HOST='localhost'
|
||||||
|
ENV BRIZO_PORT='8030'
|
||||||
|
ENV BRIZO_ADDRESS='0x00bd138abd70e2f00903268f3db08f2d25677c9e'
|
||||||
|
ENV PARITY_SCHEME='http'
|
||||||
|
ENV PARITY_HOST='localhost'
|
||||||
|
ENV PARITY_PORT='8545'
|
||||||
|
ENV SECRET_STORE_SCHEME='http'
|
||||||
|
ENV SECRET_STORE_HOST='localhost'
|
||||||
|
ENV SECRET_STORE_PORT='12001'
|
||||||
|
ENV FAUCET_SCHEME='http'
|
||||||
|
ENV FAUCET_HOST='localhost'
|
||||||
|
ENV FAUCET_PORT='3001'
|
||||||
|
|
||||||
|
ENV LISTEN_ADDRESS='0.0.0.0'
|
||||||
|
ENV LISTEN_PORT='3000'
|
||||||
|
|
||||||
|
ENTRYPOINT ["/app/frontend/scripts/docker-entrypoint.sh"]
|
@ -11,7 +11,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@oceanprotocol/art": "^2.2.0",
|
"@oceanprotocol/art": "^2.2.0",
|
||||||
"@oceanprotocol/squid": "^0.5.0",
|
"@oceanprotocol/squid": "^0.5.1",
|
||||||
"@oceanprotocol/typographies": "^0.1.0",
|
"@oceanprotocol/typographies": "^0.1.0",
|
||||||
"classnames": "^2.2.6",
|
"classnames": "^2.2.6",
|
||||||
"filesize": "^4.1.2",
|
"filesize": "^4.1.2",
|
||||||
|
@ -10,7 +10,40 @@
|
|||||||
<meta name="theme-color" content="#141414" />
|
<meta name="theme-color" content="#141414" />
|
||||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
||||||
|
|
||||||
<title>Commons Marketplace</title>
|
<title>Commons</title>
|
||||||
|
|
||||||
|
<meta
|
||||||
|
content="A marketplace to find and publish open data sets in the Ocean Network."
|
||||||
|
name="description"
|
||||||
|
/>
|
||||||
|
<meta
|
||||||
|
content="https://commons.oceanprotocol.com/share.png"
|
||||||
|
name="image"
|
||||||
|
/>
|
||||||
|
<link href="https://commons.oceanprotocol.com" rel="canonical" />
|
||||||
|
|
||||||
|
<meta content="https://commons.oceanprotocol.com" property="og:url" />
|
||||||
|
<meta content="Commons" property="og:title" />
|
||||||
|
<meta
|
||||||
|
content="A marketplace to find and publish open data sets in the Ocean Network."
|
||||||
|
property="og:description"
|
||||||
|
/>
|
||||||
|
<meta
|
||||||
|
content="https://commons.oceanprotocol.com/share.png"
|
||||||
|
property="og:image"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<meta content="summary_large_image" name="twitter:card" />
|
||||||
|
<meta content="@oceanprotocol" name="twitter:creator" />
|
||||||
|
<meta content="Commons" name="twitter:title" />
|
||||||
|
<meta
|
||||||
|
content="A marketplace to find and publish open data sets in the Ocean Network."
|
||||||
|
name="twitter:description"
|
||||||
|
/>
|
||||||
|
<meta
|
||||||
|
content="https://commons.oceanprotocol.com/share.png"
|
||||||
|
name="twitter:image"
|
||||||
|
/>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.loader {
|
.loader {
|
||||||
|
BIN
client/public/share.png
Normal file
BIN
client/public/share.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 167 KiB |
37
client/scripts/docker-entrypoint.sh
Executable file
37
client/scripts/docker-entrypoint.sh
Executable file
@ -0,0 +1,37 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
SERVICE_SCHEME=${SERVICE_SCHEME:-http}
|
||||||
|
SERVICE_HOST=${SERVICE_HOST:-localhost}
|
||||||
|
SERVICE_PORT=${SERVICE_PORT:-8545}
|
||||||
|
|
||||||
|
NODE_SCHEME=${NODE_SCHEME:-http}
|
||||||
|
NODE_HOST=${NODE_HOST:-localhost}
|
||||||
|
NODE_PORT=${NODE_PORT:-8545}
|
||||||
|
AQUARIUS_SCHEME=${AQUARIUS_SCHEME:-http}
|
||||||
|
AQUARIUS_HOST=${AQUARIUS_HOST:-localhost}
|
||||||
|
AQUARIUS_PORT=${AQUARIUS_PORT:-5000}
|
||||||
|
BRIZO_SCHEME=${BRIZO_SCHEME:-http}
|
||||||
|
BRIZO_HOST=${BRIZO_HOST:-localhost}
|
||||||
|
BRIZO_PORT=${BRIZO_PORT:-8030}
|
||||||
|
BRIZO_PASSWORD=${BRIZO_PASSWORD:-0x00bd138abd70e2f00903268f3db08f2d25677c9e}
|
||||||
|
PARITY_SCHEME=${PARITY_SCHEME:-http}
|
||||||
|
PARITY_HOST=${PARITY_HOST:-localhost}
|
||||||
|
PARITY_PORT=${PARITY_PORT:-8545}
|
||||||
|
SECRET_STORE_SCHEME=${SECRET_STORE_SCHEME:-http}
|
||||||
|
SECRET_STORE_HOST=${SECRET_STORE_HOST:-localhost}
|
||||||
|
SECRET_STORE_PORT=${SECRET_STORE_PORT:-12001}
|
||||||
|
|
||||||
|
FAUCET_SCHEME=${FAUCET_SCHEME:-http}
|
||||||
|
FAUCET_HOST=${FAUCET_HOST:-localhost}
|
||||||
|
FAUCET_PORT=${FAUCET_PORT:-443}
|
||||||
|
|
||||||
|
envsubst < /app/frontend/src/config/config.ts.template > /app/frontend/src/config/config.ts
|
||||||
|
if [ "${LOCAL_CONTRACTS}" = "true" ]; then
|
||||||
|
echo "Waiting for contracts to be generated..."
|
||||||
|
while [ ! -f "/app/frontend/node_modules/@oceanprotocol/keeper-contracts/artifacts/ready" ]; do
|
||||||
|
sleep 2
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
echo "Starting Commons..."
|
||||||
|
npm run build
|
||||||
|
serve -l tcp://"${LISTEN_ADDRESS}":"${LISTEN_PORT}" -s /app/frontend/build/
|
@ -18,7 +18,7 @@ import {
|
|||||||
faucetHost,
|
faucetHost,
|
||||||
faucetPort,
|
faucetPort,
|
||||||
faucetScheme
|
faucetScheme
|
||||||
} from './config'
|
} from './config/config'
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface Window {
|
interface Window {
|
||||||
@ -40,6 +40,7 @@ interface AppState {
|
|||||||
web3: Web3
|
web3: Web3
|
||||||
ocean: {}
|
ocean: {}
|
||||||
startLogin: () => void
|
startLogin: () => void
|
||||||
|
message: string
|
||||||
}
|
}
|
||||||
|
|
||||||
class App extends Component<{}, AppState> {
|
class App extends Component<{}, AppState> {
|
||||||
@ -94,7 +95,8 @@ class App extends Component<{}, AppState> {
|
|||||||
account: '',
|
account: '',
|
||||||
ocean: {},
|
ocean: {},
|
||||||
startLogin: this.startLogin,
|
startLogin: this.startLogin,
|
||||||
requestFromFaucet: this.requestFromFaucet
|
requestFromFaucet: this.requestFromFaucet,
|
||||||
|
message: 'Connecting to Ocean...'
|
||||||
}
|
}
|
||||||
|
|
||||||
public async componentDidMount() {
|
public async componentDidMount() {
|
||||||
@ -185,7 +187,7 @@ class App extends Component<{}, AppState> {
|
|||||||
<main className={styles.main}>
|
<main className={styles.main}>
|
||||||
{this.state.isLoading ? (
|
{this.state.isLoading ? (
|
||||||
<div className={styles.loader}>
|
<div className={styles.loader}>
|
||||||
<Spinner message="Connecting to Ocean..." />
|
<Spinner message={this.state.message} />
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<Routes />
|
<Routes />
|
||||||
|
@ -66,6 +66,7 @@
|
|||||||
padding: 0;
|
padding: 0;
|
||||||
color: $brand-pink;
|
color: $brand-pink;
|
||||||
font-size: $font-size-base;
|
font-size: $font-size-base;
|
||||||
|
font-weight: $font-weight-base;
|
||||||
font-family: inherit;
|
font-family: inherit;
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import React, { PureComponent } from 'react'
|
import React, { PureComponent } from 'react'
|
||||||
|
import { Link } from 'react-router-dom'
|
||||||
import cx from 'classnames'
|
import cx from 'classnames'
|
||||||
import styles from './Button.module.scss'
|
import styles from './Button.module.scss'
|
||||||
|
|
||||||
@ -10,6 +11,7 @@ interface ButtonProps {
|
|||||||
href?: string
|
href?: string
|
||||||
onClick?: any
|
onClick?: any
|
||||||
disabled?: boolean
|
disabled?: boolean
|
||||||
|
to?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class Button extends PureComponent<ButtonProps, any> {
|
export default class Button extends PureComponent<ButtonProps, any> {
|
||||||
@ -21,6 +23,7 @@ export default class Button extends PureComponent<ButtonProps, any> {
|
|||||||
href,
|
href,
|
||||||
children,
|
children,
|
||||||
className,
|
className,
|
||||||
|
to,
|
||||||
...props
|
...props
|
||||||
} = this.props
|
} = this.props
|
||||||
|
|
||||||
@ -32,11 +35,23 @@ export default class Button extends PureComponent<ButtonProps, any> {
|
|||||||
classes = styles.button
|
classes = styles.button
|
||||||
}
|
}
|
||||||
|
|
||||||
return href ? (
|
if (to) {
|
||||||
|
return (
|
||||||
|
<Link to={to} className={cx(classes, className)} {...props}>
|
||||||
|
{children}
|
||||||
|
</Link>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (href) {
|
||||||
|
return (
|
||||||
<a href={href} className={cx(classes, className)} {...props}>
|
<a href={href} className={cx(classes, className)} {...props}>
|
||||||
{children}
|
{children}
|
||||||
</a>
|
</a>
|
||||||
) : (
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
<button className={cx(classes, className)} {...props}>
|
<button className={cx(classes, className)} {...props}>
|
||||||
{children}
|
{children}
|
||||||
</button>
|
</button>
|
||||||
|
@ -12,8 +12,11 @@ const AssetLink = ({ asset, list }: { asset: any; list?: boolean }) => {
|
|||||||
<article className={styles.assetList}>
|
<article className={styles.assetList}>
|
||||||
<Link to={`/asset/${asset.id}`}>
|
<Link to={`/asset/${asset.id}`}>
|
||||||
<h1>{base.name}</h1>
|
<h1>{base.name}</h1>
|
||||||
<div className={styles.date} title={base.dateCreated}>
|
<div
|
||||||
{moment(base.dateCreated, 'YYYYMMDD').fromNow()}
|
className={styles.date}
|
||||||
|
title={`Published on ${base.datePublished}`}
|
||||||
|
>
|
||||||
|
{moment(base.datePublished, 'YYYYMMDD').fromNow()}
|
||||||
</div>
|
</div>
|
||||||
</Link>
|
</Link>
|
||||||
</article>
|
</article>
|
||||||
|
@ -52,7 +52,7 @@ export default class AssetsUser extends PureComponent<
|
|||||||
<div className={styles.assetsUser}>
|
<div className={styles.assetsUser}>
|
||||||
{this.props.recent && (
|
{this.props.recent && (
|
||||||
<h2 className={styles.subTitle}>
|
<h2 className={styles.subTitle}>
|
||||||
Your Latest Data Sets
|
Your Latest Published Data Sets
|
||||||
</h2>
|
</h2>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
@ -1,12 +1,28 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { NavLink } from 'react-router-dom'
|
import { NavLink } from 'react-router-dom'
|
||||||
import { ReactComponent as Logo } from '@oceanprotocol/art/logo/logo.svg'
|
import { ReactComponent as Logo } from '@oceanprotocol/art/logo/logo.svg'
|
||||||
|
import { User } from '../../context/User'
|
||||||
import AccountStatus from '../molecules/AccountStatus'
|
import AccountStatus from '../molecules/AccountStatus'
|
||||||
import styles from './Header.module.scss'
|
import styles from './Header.module.scss'
|
||||||
|
|
||||||
import menu from '../../data/menu.json'
|
import menu from '../../data/menu.json'
|
||||||
import meta from '../../data/meta.json'
|
import meta from '../../data/meta.json'
|
||||||
|
|
||||||
|
const MenuItem = ({ item, isWeb3 }: { item: any; isWeb3: boolean }) => {
|
||||||
|
if (item.web3 && !isWeb3) return null
|
||||||
|
|
||||||
|
return (
|
||||||
|
<NavLink
|
||||||
|
to={item.link}
|
||||||
|
className={styles.link}
|
||||||
|
activeClassName={styles.linkActive}
|
||||||
|
exact
|
||||||
|
>
|
||||||
|
{item.title}
|
||||||
|
</NavLink>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
const Header = () => (
|
const Header = () => (
|
||||||
<header className={styles.header}>
|
<header className={styles.header}>
|
||||||
<div className={styles.headerContent}>
|
<div className={styles.headerContent}>
|
||||||
@ -16,17 +32,17 @@ const Header = () => (
|
|||||||
</NavLink>
|
</NavLink>
|
||||||
|
|
||||||
<nav className={styles.headerMenu}>
|
<nav className={styles.headerMenu}>
|
||||||
{menu.map(item => (
|
<User.Consumer>
|
||||||
<NavLink
|
{states =>
|
||||||
|
menu.map(item => (
|
||||||
|
<MenuItem
|
||||||
key={item.title}
|
key={item.title}
|
||||||
to={item.link}
|
item={item}
|
||||||
className={styles.link}
|
isWeb3={states.isWeb3}
|
||||||
activeClassName={styles.linkActive}
|
/>
|
||||||
exact
|
))
|
||||||
>
|
}
|
||||||
{item.title}
|
</User.Consumer>
|
||||||
</NavLink>
|
|
||||||
))}
|
|
||||||
</nav>
|
</nav>
|
||||||
<AccountStatus className={styles.accountStatus} />
|
<AccountStatus className={styles.accountStatus} />
|
||||||
</div>
|
</div>
|
||||||
|
36
client/src/config/config.ts.template
Normal file
36
client/src/config/config.ts.template
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
//
|
||||||
|
// commons-server connection
|
||||||
|
//
|
||||||
|
export const serviceScheme = '${SERVICE_SCHEME}'
|
||||||
|
export const serviceHost = '${SERVICE_HOST}'
|
||||||
|
export const servicePort = '${SERVICE_PORT}'
|
||||||
|
|
||||||
|
//
|
||||||
|
// OCEAN REMOTE CONNECTIONS
|
||||||
|
//
|
||||||
|
export const nodeScheme = '${NODE_SCHEME}'
|
||||||
|
export const nodeHost = '${NODE_HOST}'
|
||||||
|
export const nodePort = '${NODE_PORT}'
|
||||||
|
|
||||||
|
export const aquariusScheme = '${AQUARIUS_SCHEME}'
|
||||||
|
export const aquariusHost = '${AQUARIUS_HOST}'
|
||||||
|
export const aquariusPort = '${AQUARIUS_PORT}'
|
||||||
|
|
||||||
|
export const brizoScheme = '${BRIZO_SCHEME}'
|
||||||
|
export const brizoHost = '${BRIZO_HOST}'
|
||||||
|
export const brizoPort = '${BRIZO_ADDRESS}'
|
||||||
|
export const brizoAddress = '${BRIZO_ADDRESS}'
|
||||||
|
|
||||||
|
export const parityScheme = '${PARITY_SCHEME}'
|
||||||
|
export const parityHost = '${PARITY_HOST}'
|
||||||
|
export const parityPort = '${PARITY_PORT}'
|
||||||
|
|
||||||
|
export const secretStoreScheme = '${SECRET_STORE_SCHEME}'
|
||||||
|
export const secretStoreHost = '${SECRET_STORE_HOST}'
|
||||||
|
export const secretStorePort = '${SECRET_STORE_PORT}'
|
||||||
|
|
||||||
|
export const faucetScheme = '${FAUCET_SCHEME}'
|
||||||
|
export const faucetHost = '${FAUCET_HOST}'
|
||||||
|
export const faucetPort = '${FAUCET_PORT}'
|
||||||
|
|
||||||
|
export const verbose = true
|
@ -1,22 +1,21 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"title": "Publish",
|
"title": "Publish",
|
||||||
"link": "/publish"
|
"link": "/publish",
|
||||||
|
"web3": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"title": "History",
|
"title": "History",
|
||||||
"link": "/history"
|
"link": "/history",
|
||||||
|
"web3": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"title": "Faucet",
|
"title": "Faucet",
|
||||||
"link": "/faucet"
|
"link": "/faucet",
|
||||||
|
"web3": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"title": "About",
|
"title": "About",
|
||||||
"link": "/about"
|
"link": "/about"
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Styleguide",
|
|
||||||
"link": "/styleguide"
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -18,7 +18,7 @@ import {
|
|||||||
secretStorePort,
|
secretStorePort,
|
||||||
secretStoreScheme,
|
secretStoreScheme,
|
||||||
verbose
|
verbose
|
||||||
} from './config'
|
} from './config/config'
|
||||||
|
|
||||||
export async function provideOcean() {
|
export async function provideOcean() {
|
||||||
const nodeUri = `${nodeScheme}://${nodeHost}:${nodePort}`
|
const nodeUri = `${nodeScheme}://${nodeHost}:${nodePort}`
|
||||||
|
@ -10,6 +10,13 @@ interface AssetDetailsProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default class AssetDetails extends PureComponent<AssetDetailsProps> {
|
export default class AssetDetails extends PureComponent<AssetDetailsProps> {
|
||||||
|
private datafilesLine = (files: any) => {
|
||||||
|
if (files.length === 1) {
|
||||||
|
return <span>{files.length} data file</span>
|
||||||
|
}
|
||||||
|
return <span>{files.length} data files</span>
|
||||||
|
}
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
const { metadata, ddo } = this.props
|
const { metadata, ddo } = this.props
|
||||||
const { base } = metadata
|
const { base } = metadata
|
||||||
@ -43,9 +50,7 @@ export default class AssetDetails extends PureComponent<AssetDetailsProps> {
|
|||||||
</Link>
|
</Link>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{base.files && (
|
{base.files && this.datafilesLine(base.files)}
|
||||||
<span>{base.files.length} data files</span>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</aside>
|
</aside>
|
||||||
|
|
||||||
@ -79,9 +84,9 @@ export default class AssetDetails extends PureComponent<AssetDetailsProps> {
|
|||||||
ddo={ddo}
|
ddo={ddo}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<pre>
|
{/* <pre>
|
||||||
<code>{JSON.stringify(metadata, null, 2)}</code>
|
<code>{JSON.stringify(metadata, null, 2)}</code>
|
||||||
</pre>
|
</pre> */}
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
60
client/src/routes/Details/AssetFile.module.scss
Normal file
60
client/src/routes/Details/AssetFile.module.scss
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
@import '../../styles/variables';
|
||||||
|
|
||||||
|
.buttonMain {
|
||||||
|
margin: auto;
|
||||||
|
margin-bottom: $spacer / 2;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error {
|
||||||
|
text-align: center;
|
||||||
|
color: $red;
|
||||||
|
font-size: $font-size-small;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fileWrap {
|
||||||
|
margin-left: $spacer / 4;
|
||||||
|
margin-right: $spacer / 4;
|
||||||
|
margin-bottom: $spacer * $line-height;
|
||||||
|
flex: 1 1 100%;
|
||||||
|
|
||||||
|
@media (min-width: $break-point--small) {
|
||||||
|
flex-basis: calc(100% / 3 - #{$spacer} / 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.file {
|
||||||
|
display: inline-block;
|
||||||
|
background: $brand-grey;
|
||||||
|
padding: $spacer $spacer / 2;
|
||||||
|
margin-bottom: $spacer / 2;
|
||||||
|
text-align: left;
|
||||||
|
position: relative;
|
||||||
|
min-height: 100px;
|
||||||
|
|
||||||
|
&:before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
border-top: 1rem solid $body-background;
|
||||||
|
border-left: 1rem solid transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
li {
|
||||||
|
font-size: $font-size-small;
|
||||||
|
font-weight: $font-weight-bold;
|
||||||
|
color: $brand-white;
|
||||||
|
|
||||||
|
&:before {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// move spinner a bit up
|
||||||
|
+ div {
|
||||||
|
margin-top: $spacer / 2;
|
||||||
|
}
|
||||||
|
}
|
99
client/src/routes/Details/AssetFile.tsx
Normal file
99
client/src/routes/Details/AssetFile.tsx
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
import React, { PureComponent } from 'react'
|
||||||
|
import { Logger } from '@oceanprotocol/squid'
|
||||||
|
import filesize from 'filesize'
|
||||||
|
import { User } from '../../context/User'
|
||||||
|
import Button from '../../components/atoms/Button'
|
||||||
|
import Spinner from '../../components/atoms/Spinner'
|
||||||
|
import styles from './AssetFile.module.scss'
|
||||||
|
|
||||||
|
interface AssetFileProps {
|
||||||
|
file: any
|
||||||
|
ddo: any
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AssetFileState {
|
||||||
|
isLoading: boolean
|
||||||
|
error: string
|
||||||
|
message: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class AssetFile extends PureComponent<
|
||||||
|
AssetFileProps,
|
||||||
|
AssetFileState
|
||||||
|
> {
|
||||||
|
public state = {
|
||||||
|
isLoading: false,
|
||||||
|
error: '',
|
||||||
|
message: 'Decrypting file, please sign...'
|
||||||
|
}
|
||||||
|
|
||||||
|
private resetState = () => this.setState({ isLoading: true, error: '' })
|
||||||
|
|
||||||
|
private purchaseAsset = async (ddo: any, index: number) => {
|
||||||
|
this.resetState()
|
||||||
|
|
||||||
|
const { ocean } = this.context
|
||||||
|
const accounts = await ocean.accounts.list()
|
||||||
|
|
||||||
|
try {
|
||||||
|
const service = ddo.findServiceByType('Access')
|
||||||
|
const agreementId = await ocean.assets.order(
|
||||||
|
ddo.id,
|
||||||
|
service.serviceDefinitionId,
|
||||||
|
accounts[0]
|
||||||
|
)
|
||||||
|
|
||||||
|
const path = await ocean.assets.consume(
|
||||||
|
agreementId,
|
||||||
|
ddo.id,
|
||||||
|
service.serviceDefinitionId,
|
||||||
|
accounts[0],
|
||||||
|
'',
|
||||||
|
index
|
||||||
|
)
|
||||||
|
Logger.log('path', path)
|
||||||
|
|
||||||
|
this.setState({ isLoading: false })
|
||||||
|
} catch (error) {
|
||||||
|
Logger.log('error', error)
|
||||||
|
this.setState({ isLoading: false, error: error.message })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public render() {
|
||||||
|
const { ddo, file } = this.props
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={styles.fileWrap}>
|
||||||
|
<ul key={file.index} className={styles.file}>
|
||||||
|
<li>
|
||||||
|
{file.contentType && file.contentType.split('/')[1]}
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
{file.contentLength && filesize(file.contentLength)}
|
||||||
|
</li>
|
||||||
|
{/* <li>{file.encoding}</li> */}
|
||||||
|
{/* <li>{file.compression}</li> */}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
{this.state.isLoading ? (
|
||||||
|
<Spinner message={this.state.message} />
|
||||||
|
) : (
|
||||||
|
<Button
|
||||||
|
primary
|
||||||
|
className={styles.buttonMain}
|
||||||
|
onClick={() => this.purchaseAsset(ddo, file.index)}
|
||||||
|
>
|
||||||
|
Get file
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{this.state.error !== '' && (
|
||||||
|
<div className={styles.error}>{this.state.error}</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AssetFile.contextType = User
|
@ -1,36 +1,8 @@
|
|||||||
@import '../../styles/variables';
|
@import '../../styles/variables';
|
||||||
|
|
||||||
.buttonMain {
|
|
||||||
margin: auto;
|
|
||||||
margin-bottom: $spacer / 2;
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.error {
|
|
||||||
text-align: center;
|
|
||||||
color: $red;
|
|
||||||
font-size: $font-size-small;
|
|
||||||
}
|
|
||||||
|
|
||||||
.files {
|
.files {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
.file {
|
justify-content: center;
|
||||||
display: inline-block;
|
|
||||||
border: .1rem solid $brand-grey-light;
|
|
||||||
padding: $spacer $spacer / 2;
|
|
||||||
text-align: left;
|
|
||||||
margin-left: $spacer / 4;
|
|
||||||
margin-right: $spacer / 4;
|
|
||||||
|
|
||||||
li {
|
|
||||||
font-size: $font-size-small;
|
|
||||||
font-weight: $font-weight-bold;
|
|
||||||
color: $brand-grey-light;
|
|
||||||
|
|
||||||
&:before {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,51 +1,11 @@
|
|||||||
import React, { PureComponent } from 'react'
|
import React, { PureComponent } from 'react'
|
||||||
import { Logger } from '@oceanprotocol/squid'
|
import AssetFile from './AssetFile'
|
||||||
import filesize from 'filesize'
|
|
||||||
import { User } from '../../context/User'
|
|
||||||
import Button from '../../components/atoms/Button'
|
|
||||||
import Spinner from '../../components/atoms/Spinner'
|
|
||||||
import styles from './AssetFilesDetails.module.scss'
|
import styles from './AssetFilesDetails.module.scss'
|
||||||
|
|
||||||
interface AssetFilesDetailsProps {
|
export default class AssetFilesDetails extends PureComponent<{
|
||||||
files: any[]
|
files: any[]
|
||||||
ddo: any
|
ddo: any
|
||||||
}
|
}> {
|
||||||
|
|
||||||
export default class AssetFilesDetails extends PureComponent<
|
|
||||||
AssetFilesDetailsProps
|
|
||||||
> {
|
|
||||||
public state = { isLoading: false, error: null }
|
|
||||||
|
|
||||||
private purchaseAsset = async (ddo: any) => {
|
|
||||||
this.setState({ isLoading: true, error: null })
|
|
||||||
|
|
||||||
const { ocean } = this.context
|
|
||||||
const accounts = await ocean.accounts.list()
|
|
||||||
|
|
||||||
try {
|
|
||||||
const service = ddo.findServiceByType('Access')
|
|
||||||
const agreementId = await ocean.assets.order(
|
|
||||||
ddo.id,
|
|
||||||
service.serviceDefinitionId,
|
|
||||||
accounts[0]
|
|
||||||
)
|
|
||||||
|
|
||||||
const path = await ocean.assets.consume(
|
|
||||||
agreementId,
|
|
||||||
ddo.id,
|
|
||||||
service.serviceDefinitionId,
|
|
||||||
accounts[0],
|
|
||||||
''
|
|
||||||
)
|
|
||||||
Logger.log('path', path)
|
|
||||||
|
|
||||||
this.setState({ isLoading: false })
|
|
||||||
} catch (error) {
|
|
||||||
Logger.log('error', error)
|
|
||||||
this.setState({ isLoading: false, error: error.message })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
const { files, ddo } = this.props
|
const { files, ddo } = this.props
|
||||||
|
|
||||||
@ -53,41 +13,12 @@ export default class AssetFilesDetails extends PureComponent<
|
|||||||
<>
|
<>
|
||||||
<div className={styles.files}>
|
<div className={styles.files}>
|
||||||
{files.map(file => (
|
{files.map(file => (
|
||||||
<ul key={file.index} className={styles.file}>
|
<AssetFile key={file.index} ddo={ddo} file={file} />
|
||||||
<li>
|
|
||||||
{file.contentType &&
|
|
||||||
file.contentType.split('/')[1]}
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
{file.contentLength &&
|
|
||||||
filesize(file.contentLength)}
|
|
||||||
</li>
|
|
||||||
{/* <li>{file.encoding}</li> */}
|
|
||||||
{/* <li>{file.compression}</li> */}
|
|
||||||
</ul>
|
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{this.state.isLoading ? (
|
|
||||||
<Spinner message="Decrypting files, please sign with your wallet..." />
|
|
||||||
) : (
|
|
||||||
<Button
|
|
||||||
primary
|
|
||||||
className={styles.buttonMain}
|
|
||||||
onClick={() => this.purchaseAsset(ddo)}
|
|
||||||
>
|
|
||||||
Get asset files
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{this.state.error && (
|
|
||||||
<div className={styles.error}>{this.state.error}</div>
|
|
||||||
)}
|
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<div>No files attached.</div>
|
<div>No files attached.</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AssetFilesDetails.contextType = User
|
|
||||||
|
@ -6,7 +6,7 @@ import ItemForm from './ItemForm'
|
|||||||
import Item from './Item'
|
import Item from './Item'
|
||||||
import styles from './index.module.scss'
|
import styles from './index.module.scss'
|
||||||
|
|
||||||
import { serviceHost, servicePort, serviceScheme } from '../../../config'
|
import { serviceHost, servicePort, serviceScheme } from '../../../config/config'
|
||||||
|
|
||||||
interface File {
|
interface File {
|
||||||
url: string
|
url: string
|
||||||
|
@ -3,3 +3,35 @@
|
|||||||
.message {
|
.message {
|
||||||
margin-bottom: $spacer;
|
margin-bottom: $spacer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.success {
|
||||||
|
composes: message;
|
||||||
|
background: $green;
|
||||||
|
padding: $spacer / 1.5;
|
||||||
|
border-radius: $border-radius;
|
||||||
|
color: $brand-white;
|
||||||
|
font-weight: $font-weight-bold;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
&,
|
||||||
|
a,
|
||||||
|
button {
|
||||||
|
color: $brand-white;
|
||||||
|
}
|
||||||
|
|
||||||
|
a,
|
||||||
|
button {
|
||||||
|
transition: color .2s ease-out;
|
||||||
|
|
||||||
|
&:hover,
|
||||||
|
&:focus {
|
||||||
|
color: $brand-pink;
|
||||||
|
transform: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
display: inline-block;
|
||||||
|
margin-right: $spacer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import React, { PureComponent } from 'react'
|
import React, { PureComponent } from 'react'
|
||||||
import Web3message from '../../components/organisms/Web3message'
|
import Web3message from '../../components/organisms/Web3message'
|
||||||
import Spinner from '../../components/atoms/Spinner'
|
import Spinner from '../../components/atoms/Spinner'
|
||||||
|
import Button from '../../components/atoms/Button'
|
||||||
import styles from './StepRegisterContent.module.scss'
|
import styles from './StepRegisterContent.module.scss'
|
||||||
|
|
||||||
interface StepRegisterContentProps {
|
interface StepRegisterContentProps {
|
||||||
@ -26,11 +27,14 @@ export default class StepRegisterContent extends PureComponent<
|
|||||||
)
|
)
|
||||||
|
|
||||||
public publishedState = () => (
|
public publishedState = () => (
|
||||||
<div className={styles.message}>
|
<div className={styles.success}>
|
||||||
Your asset is published! See it{' '}
|
<p>Your asset is published!</p>
|
||||||
<a href={'/asset/' + this.props.state.publishedDid}>here</a>, submit
|
<Button link to={'/asset/' + this.props.state.publishedDid}>
|
||||||
another asset by clicking{' '}
|
See published asset
|
||||||
<a onClick={() => this.props.toStart()}>here</a>
|
</Button>
|
||||||
|
<Button link onClick={() => this.props.toStart()}>
|
||||||
|
Publish another asset
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -38,7 +42,6 @@ export default class StepRegisterContent extends PureComponent<
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Web3message />
|
<Web3message />
|
||||||
|
|
||||||
{this.props.state.isPublishing ? (
|
{this.props.state.isPublishing ? (
|
||||||
this.publishingState()
|
this.publishingState()
|
||||||
) : this.props.state.publishingError ? (
|
) : this.props.state.publishingError ? (
|
||||||
|
@ -18,6 +18,8 @@ $yellow: #eac146;
|
|||||||
|
|
||||||
$brand-gradient: linear-gradient(to right bottom, $brand-purple, $brand-pink);
|
$brand-gradient: linear-gradient(to right bottom, $brand-purple, $brand-pink);
|
||||||
|
|
||||||
|
$body-background: darken($brand-white, 1%);
|
||||||
|
|
||||||
// Fonts
|
// Fonts
|
||||||
$font-family-base: 'Sharp Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI',
|
$font-family-base: 'Sharp Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI',
|
||||||
Helvetica, Arial, sans-serif;
|
Helvetica, Arial, sans-serif;
|
||||||
|
@ -29,7 +29,7 @@ body {
|
|||||||
font-family: $font-family-base;
|
font-family: $font-family-base;
|
||||||
font-weight: $font-weight-base;
|
font-weight: $font-weight-base;
|
||||||
line-height: $line-height;
|
line-height: $line-height;
|
||||||
background: darken($brand-white, 1%);
|
background: $body-background;
|
||||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
@ -15,5 +15,5 @@
|
|||||||
"noEmit": true,
|
"noEmit": true,
|
||||||
"jsx": "preserve"
|
"jsx": "preserve"
|
||||||
},
|
},
|
||||||
"include": ["src"]
|
"include": ["src", "config/config.ts"]
|
||||||
}
|
}
|
||||||
|
24
docker-compose.yml
Normal file
24
docker-compose.yml
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
version: '3.4'
|
||||||
|
|
||||||
|
services:
|
||||||
|
|
||||||
|
client:
|
||||||
|
build:
|
||||||
|
context: ./client
|
||||||
|
dockerfile: ./Dockerfile
|
||||||
|
ports:
|
||||||
|
- 3000:3000
|
||||||
|
depends_on:
|
||||||
|
- server
|
||||||
|
environment:
|
||||||
|
- SERVICE_SCHEME=http
|
||||||
|
- SERVICE_HOST=localhost
|
||||||
|
- SERVICE_PORT=4000
|
||||||
|
|
||||||
|
server:
|
||||||
|
build:
|
||||||
|
context: ./server
|
||||||
|
dockerfile: ./Dockerfile
|
||||||
|
ports:
|
||||||
|
- 4000:4000
|
||||||
|
command: npm run start
|
10
server/Dockerfile
Normal file
10
server/Dockerfile
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
FROM node:11-alpine
|
||||||
|
LABEL maintainer="Ocean Protocol <devops@oceanprotocol.com>"
|
||||||
|
|
||||||
|
WORKDIR /app/backend/
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
RUN npm install
|
||||||
|
|
||||||
|
RUN npm run build
|
Loading…
x
Reference in New Issue
Block a user