Merge branch 'master' into feature/network_switcher

This commit is contained in:
Matthias Kretschmann 2020-02-01 15:46:36 +01:00
commit 40ed5e101e
Signed by: m
GPG Key ID: 606EEEF3C479A91F
49 changed files with 9132 additions and 8186 deletions

View File

@ -28,10 +28,10 @@ env:
- IPFS_GATEWAY_URI="https://ipfs.oceanprotocol.com" - IPFS_GATEWAY_URI="https://ipfs.oceanprotocol.com"
# start Barge with these versions # start Barge with these versions
- BRIZO_VERSION=v0.7.2 - BRIZO_VERSION=v0.8.1
- AQUARIUS_VERSION=v1.0.5 - AQUARIUS_VERSION=v1.0.5
- KEEPER_VERSION=v0.12.7 - KEEPER_VERSION=v0.13.2
- EVENTS_HANDLER_VERSION=v0.3.4 - EVENTS_HANDLER_VERSION=v0.4.4
- KEEPER_OWNER_ROLE_ADDRESS="0xe2DD09d719Da89e5a3D0F2549c7E24566e947260" - KEEPER_OWNER_ROLE_ADDRESS="0xe2DD09d719Da89e5a3D0F2549c7E24566e947260"
- FAUCET_TIMESPAN=0 - FAUCET_TIMESPAN=0

View File

@ -4,6 +4,25 @@ All notable changes to this project will be documented in this file. Dates are d
Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
#### [v2.2.0](https://github.com/oceanprotocol/commons/compare/v2.1.0...v2.2.0)
> 1 February 2020
- bump to react-scripts v3.3 [`#209`](https://github.com/oceanprotocol/commons/pull/209)
- package updates [`65b72e5`](https://github.com/oceanprotocol/commons/commit/65b72e597d16f8660f74b0b3a491aba723488a56)
- fix Travis [`3e814b9`](https://github.com/oceanprotocol/commons/commit/3e814b98a7f990cfee6b910f57eb02cdd1a767f1)
- package updates [`8089a7a`](https://github.com/oceanprotocol/commons/commit/8089a7aa3e4504e1defb3a6809e4d8b4c2a823fb)
#### [v2.1.0](https://github.com/oceanprotocol/commons/compare/v2.0.1...v2.1.0)
> 23 January 2020
- Fix search code duplication [`#216`](https://github.com/oceanprotocol/commons/pull/216)
- bump to keeper-contracts v0.13 [`#210`](https://github.com/oceanprotocol/commons/pull/210)
- bump to keeper-contracts v0.13.0 [`5ba5cd9`](https://github.com/oceanprotocol/commons/commit/5ba5cd9e20f7bc7ad7aebeb4b9c54f0aea549786)
- fix code duplication [`c5ea3b7`](https://github.com/oceanprotocol/commons/commit/c5ea3b7c8a989b7c9239cc4292de53680b36c06b)
- bump all components [`37296c5`](https://github.com/oceanprotocol/commons/commit/37296c502e24a1e0aedc021bfa666dd33dce323d)
#### [v2.0.1](https://github.com/oceanprotocol/commons/compare/v2.0.0...v2.0.1) #### [v2.0.1](https://github.com/oceanprotocol/commons/compare/v2.0.0...v2.0.1)
> 7 January 2020 > 7 January 2020
@ -11,6 +30,7 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
- more additionalInformation checks [`#213`](https://github.com/oceanprotocol/commons/pull/213) - more additionalInformation checks [`#213`](https://github.com/oceanprotocol/commons/pull/213)
- remove editorconfig [`#211`](https://github.com/oceanprotocol/commons/pull/211) - remove editorconfig [`#211`](https://github.com/oceanprotocol/commons/pull/211)
- remove editorconfig, define all styling in prettierrc [`f8dfaa4`](https://github.com/oceanprotocol/commons/commit/f8dfaa438c42e9d6c25ae9ac096129da95e431c3) - remove editorconfig, define all styling in prettierrc [`f8dfaa4`](https://github.com/oceanprotocol/commons/commit/f8dfaa438c42e9d6c25ae9ac096129da95e431c3)
- Release 2.0.1 [`e9e5dd9`](https://github.com/oceanprotocol/commons/commit/e9e5dd9049bd60041d1483f102fdd6749b5a9b70)
#### [v2.0.0](https://github.com/oceanprotocol/commons/compare/v2.0.0-beta.3...v2.0.0) #### [v2.0.0](https://github.com/oceanprotocol/commons/compare/v2.0.0-beta.3...v2.0.0)

12127
client/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
{ {
"name": "commons-client", "name": "commons-client",
"description": "Ocean Protocol marketplace frontend to explore, download, and publish open data sets.", "description": "Ocean Protocol marketplace frontend to explore, download, and publish open data sets.",
"version": "2.0.1", "version": "2.2.0",
"license": "Apache-2.0", "license": "Apache-2.0",
"scripts": { "scripts": {
"start": "react-scripts start", "start": "react-scripts start",
@ -14,62 +14,59 @@
}, },
"dependencies": { "dependencies": {
"@oceanprotocol/art": "^2.2.0", "@oceanprotocol/art": "^2.2.0",
"@oceanprotocol/squid": "^1.0.0", "@oceanprotocol/squid": "^1.3.0",
"@oceanprotocol/typographies": "^0.1.0", "@oceanprotocol/typographies": "^0.1.0",
"@sindresorhus/slugify": "^0.9.1", "@sindresorhus/slugify": "^0.10.0",
"@truffle/hdwallet-provider": "^1.0.26", "@truffle/hdwallet-provider": "^1.0.30",
"axios": "^0.19.0", "axios": "^0.19.2",
"bip39": "^3.0.2", "bip39": "^3.0.2",
"classnames": "^2.2.6", "classnames": "^2.2.6",
"ethereum-blockies": "github:MyEtherWallet/blockies", "ethereum-blockies": "github:MyEtherWallet/blockies",
"filesize": "^6.0.1", "filesize": "^6.0.1",
"history": "^4.10.1", "history": "^4.10.1",
"ipfs-http-client": "^39.0.2", "ipfs-http-client": "39.0.2",
"is-url-superb": "^3.0.0", "is-url-superb": "^3.0.0",
"moment": "^2.24.0", "moment": "^2.24.0",
"query-string": "^6.9.0", "node-sass": "^4.13.1",
"query-string": "^6.10.1",
"react": "^16.12.0", "react": "^16.12.0",
"react-collapsed": "^2.2.3", "react-collapsed": "^2.2.3",
"react-datepicker": "^2.10.1", "react-datepicker": "^2.11.0",
"react-dom": "^16.12.0", "react-dom": "^16.12.0",
"react-dotdotdot": "^1.3.1", "react-dotdotdot": "^1.3.1",
"react-dropzone": "^10.2.1", "react-dropzone": "^10.2.1",
"react-ga": "^2.7.0", "react-ga": "^2.7.0",
"react-helmet": "^5.2.1", "react-helmet": "^5.2.1",
"react-markdown": "^4.2.2", "react-markdown": "^4.3.1",
"react-modal": "^3.11.1", "react-modal": "^3.11.1",
"react-moment": "^0.9.6", "react-moment": "^0.9.7",
"react-paginate": "^6.3.2", "react-paginate": "^6.3.2",
"react-popper": "^1.3.6", "react-popper": "^1.3.7",
"react-router-dom": "^5.1.2", "react-router-dom": "^5.1.2",
"react-transition-group": "^4.3.0", "react-transition-group": "^4.3.0",
"shortid": "^2.2.15", "shortid": "^2.2.15",
"web3": "^1.2.4" "web3": "^1.2.5"
}, },
"devDependencies": { "devDependencies": {
"@react-mock/state": "^0.1.8", "@react-mock/state": "^0.1.8",
"@testing-library/jest-dom": "^4.2.4", "@testing-library/jest-dom": "^5.0.2",
"@testing-library/react": "^9.3.2", "@testing-library/react": "^9.4.0",
"@types/classnames": "^2.2.9", "@types/classnames": "^2.2.9",
"@types/is-url": "^1.2.28", "@types/is-url": "^1.2.28",
"@types/jest": "^24.0.23", "@types/jest": "^24.9.1",
"@types/react": "^16.9.15", "@types/react": "^16.9.19",
"@types/react-datepicker": "^2.9.5", "@types/react-datepicker": "^2.10.0",
"@types/react-dom": "^16.9.4", "@types/react-dom": "^16.9.5",
"@types/react-helmet": "^5.0.14", "@types/react-helmet": "^5.0.15",
"@types/react-modal": "^3.10.0", "@types/react-modal": "^3.10.4",
"@types/react-paginate": "^6.2.1", "@types/react-paginate": "^6.2.1",
"@types/react-router-dom": "^5.1.3", "@types/react-router-dom": "^5.1.3",
"@types/react-transition-group": "^4.2.3", "@types/react-transition-group": "^4.2.3",
"@types/shortid": "^0.0.29", "@types/shortid": "^0.0.29",
"@typescript-eslint/eslint-plugin": "^1.6.0", "jest-mock-axios": "^3.2.0",
"@typescript-eslint/parser": "^1.6.0", "react-scripts": "^3.3.1",
"eslint": "^5.16.0", "source-map-explorer": "^2.2.2",
"jest-mock-axios": "^3.1.2", "typescript": "^3.7.5"
"node-sass": "^4.13.0",
"react-scripts": "3.0.1",
"source-map-explorer": "^2.1.2",
"typescript": "^3.7.3"
}, },
"repository": { "repository": {
"type": "git", "type": "git",

View File

@ -2,7 +2,7 @@ import React from 'react'
import { render } from '@testing-library/react' import { render } from '@testing-library/react'
import App from './App' import App from './App'
import { User } from './context' import { User } from './context'
import { userMock, userMockConnected } from '../__mocks__/user-mock' import { userMock, userMockConnected } from './__mocks__/user-mock'
describe('App', () => { describe('App', () => {
it('should be able to run tests', () => { it('should be able to run tests', () => {

View File

@ -3,7 +3,7 @@ import { BrowserRouter as Router } from 'react-router-dom'
import { render } from '@testing-library/react' import { render } from '@testing-library/react'
import Routes from './Routes' import Routes from './Routes'
import { User } from './context' import { User } from './context'
import { userMockConnected } from '../__mocks__/user-mock' import { userMockConnected } from './__mocks__/user-mock'
describe('Routes', () => { describe('Routes', () => {
it('renders without crashing', () => { it('renders without crashing', () => {

View File

@ -3,7 +3,7 @@ import { render, fireEvent } from '@testing-library/react'
import { toDataUrl } from 'ethereum-blockies' import { toDataUrl } from 'ethereum-blockies'
import Account from './Account' import Account from './Account'
import { User } from '../../context' import { User } from '../../context'
import { userMockConnected } from '../../../__mocks__/user-mock' import { userMockConnected } from '../../__mocks__/user-mock'
describe('Account', () => { describe('Account', () => {
it('renders without crashing', () => { it('renders without crashing', () => {

View File

@ -56,7 +56,7 @@ export default class Input extends PureComponent<InputProps, InputState> {
} }
} }
public toggleFocus = () => { public handleFocus = () => {
this.setState({ isFocused: !this.state.isFocused }) this.setState({ isFocused: !this.state.isFocused })
} }
@ -94,8 +94,8 @@ export default class Input extends PureComponent<InputProps, InputState> {
className={styles.select} className={styles.select}
name={name} name={name}
required={required} required={required}
onFocus={this.toggleFocus} onFocus={this.handleFocus}
onBlur={this.toggleFocus} onBlur={this.handleFocus}
onChange={onChange} onChange={onChange}
value={value} value={value}
> >
@ -117,8 +117,8 @@ export default class Input extends PureComponent<InputProps, InputState> {
<textarea <textarea
id={name} id={name}
className={styles.input} className={styles.input}
onFocus={this.toggleFocus} onFocus={this.handleFocus}
onBlur={this.toggleFocus} onBlur={this.handleFocus}
{...this.props} {...this.props}
/> />
</div> </div>
@ -154,8 +154,8 @@ export default class Input extends PureComponent<InputProps, InputState> {
selected={this.state.dateCreated} selected={this.state.dateCreated}
onChange={this.handleDateChange} onChange={this.handleDateChange}
className={styles.input} className={styles.input}
onFocus={this.toggleFocus} onFocus={this.handleFocus}
onBlur={this.toggleFocus} onBlur={this.handleFocus}
id={name} id={name}
name={name} name={name}
/> />
@ -170,8 +170,8 @@ export default class Input extends PureComponent<InputProps, InputState> {
id={name} id={name}
type={type || 'text'} type={type || 'text'}
className={styles.input} className={styles.input}
onFocus={this.toggleFocus} onFocus={this.handleFocus}
onBlur={this.toggleFocus} onBlur={this.handleFocus}
{...this.props} {...this.props}
/> />
{group} {group}
@ -181,8 +181,8 @@ export default class Input extends PureComponent<InputProps, InputState> {
id={name} id={name}
type={type || 'text'} type={type || 'text'}
className={styles.input} className={styles.input}
onFocus={this.toggleFocus} onFocus={this.handleFocus}
onBlur={this.toggleFocus} onBlur={this.handleFocus}
{...this.props} {...this.props}
/> />
)} )}

View File

@ -8,7 +8,7 @@ const Modal = ({
title, title,
description, description,
isOpen, isOpen,
toggleModal, onToggleModal,
children, children,
onAfterOpen, onAfterOpen,
onRequestClose, onRequestClose,
@ -17,7 +17,7 @@ const Modal = ({
title: string title: string
description?: string description?: string
isOpen: boolean isOpen: boolean
toggleModal: () => void onToggleModal: () => void
children: any children: any
onAfterOpen?: () => void onAfterOpen?: () => void
onRequestClose?: () => void onRequestClose?: () => void
@ -34,7 +34,7 @@ const Modal = ({
> >
<button <button
className={styles.close} className={styles.close}
onClick={toggleModal} onClick={onToggleModal}
data-testid="closeModal" data-testid="closeModal"
> >
&times; &times;

View File

@ -1,8 +1,8 @@
import React from 'react' import React from 'react'
import { render } from '@testing-library/react' import { render } from '@testing-library/react'
import Popover from './Popover' import Popover from './Popover'
import { userMock, userMockConnected } from '../../../../__mocks__/user-mock' import { userMock, userMockConnected } from '../../../__mocks__/user-mock'
import { marketMock } from '../../../../__mocks__/market-mock' import { marketMock } from '../../../__mocks__/market-mock'
import { User, Market } from '../../../context' import { User, Market } from '../../../context'
describe('Popover', () => { describe('Popover', () => {

View File

@ -18,36 +18,32 @@ export default class Popover extends PureComponent<{
ref={this.props.forwardedRef} ref={this.props.forwardedRef}
style={this.props.style} style={this.props.style}
> >
{ <div className={styles.popoverInfoline}>
<> <Account />
</div>
{account && balance && (
<div className={styles.popoverInfoline}>
<span
className={styles.balance}
title={(balance.eth / 1e18).toFixed(10)}
>
<strong>
{(balance.eth / 1e18).toFixed(3).slice(0, -1)}
</strong>{' '}
ETH
</span>
<span className={styles.balance}>
<strong>{balance.ocn}</strong> OCEAN
</span>
</div>
)}
<Market.Consumer>
{market => (
<div className={styles.popoverInfoline}> <div className={styles.popoverInfoline}>
<Account /> {network && !market.networkMatch
</div> ? `Please connect to Custom RPC
{account && balance && (
<div className={styles.popoverInfoline}>
<span
className={styles.balance}
title={(balance.eth / 1e18).toFixed(10)}
>
<strong>
{(balance.eth / 1e18)
.toFixed(3)
.slice(0, -1)}
</strong>{' '}
ETH
</span>
<span className={styles.balance}>
<strong>{balance.ocn}</strong> OCEAN
</span>
</div>
)}
<Market.Consumer>
{market => (
<div className={styles.popoverInfoline}>
{network && !market.networkMatch
? `Please connect to Custom RPC
${ ${
market.network === 'Pacific' market.network === 'Pacific'
? 'https://pacific.oceanprotocol.com' ? 'https://pacific.oceanprotocol.com'
@ -57,13 +53,10 @@ export default class Popover extends PureComponent<{
? 'https://duero.dev-ocean.com' ? 'https://duero.dev-ocean.com'
: 'http://localhost:8545' : 'http://localhost:8545'
}` }`
: network && : network && `Connected to ${network} network`}
`Connected to ${network} network`} </div>
</div> )}
)} </Market.Consumer>
</Market.Consumer>
</>
}
</div> </div>
) )
} }

View File

@ -0,0 +1,36 @@
@import '../../styles/variables';
.results {
display: grid;
grid-template-columns: 1fr;
grid-gap: $spacer;
max-width: calc(18rem + #{$spacer * 2});
margin: auto;
margin-top: $spacer * 2;
@media (min-width: $break-point--small) {
margin-left: 0;
margin-right: 0;
max-width: none;
grid-template-columns: repeat(2, 1fr);
}
@media (min-width: $break-point--medium) {
grid-template-columns: repeat(3, 1fr);
}
}
.simple {
composes: results;
margin-top: 0;
@media (min-width: $break-point--medium) {
grid-template-columns: repeat(2, 1fr);
}
}
.empty {
text-align: center;
margin-top: $spacer * 4;
color: $brand-grey-light;
}

View File

@ -0,0 +1,40 @@
import React from 'react'
import { Link } from 'react-router-dom'
import { DDO } from '@oceanprotocol/squid'
import Spinner from '../atoms/Spinner'
import AssetTeaser from './AssetTeaser'
import styles from './SearchResults.module.scss'
export interface SearchResultsState {
results: DDO[]
totalResults: number
offset: number
totalPages: number
currentPage: number
isLoading: boolean
}
export default function SearchResults({
isLoading,
results,
simpleGrid
}: {
isLoading: boolean
results: DDO[]
simpleGrid?: boolean
}) {
return isLoading ? (
<Spinner message="Searching..." />
) : results && results.length ? (
<div className={simpleGrid ? styles.simple : styles.results}>
{results.map((asset: any) => (
<AssetTeaser key={asset.id} asset={asset} />
))}
</div>
) : (
<div className={styles.empty}>
<p>No Data Sets Found.</p>
<Link to="/publish">+ Publish A Data Set</Link>
</div>
)
}

View File

@ -5,7 +5,7 @@ import { StateMock } from '@react-mock/state'
import VersionNumbers from '.' import VersionNumbers from '.'
import { User } from '../../../context' import { User } from '../../../context'
import { userMockConnected } from '../../../../__mocks__/user-mock' import { userMockConnected } from '../../../__mocks__/user-mock'
afterEach(() => { afterEach(() => {
mockAxios.reset() mockAxios.reset()

View File

@ -3,7 +3,7 @@ import { BrowserRouter } from 'react-router-dom'
import { render } from '@testing-library/react' import { render } from '@testing-library/react'
import AssetsLatest from './AssetsLatest' import AssetsLatest from './AssetsLatest'
import { User } from '../../context' import { User } from '../../context'
import { userMockConnected } from '../../../__mocks__/user-mock' import { userMockConnected } from '../../__mocks__/user-mock'
describe('AssetsLatest', () => { describe('AssetsLatest', () => {
it('renders without crashing', () => { it('renders without crashing', () => {

View File

@ -74,13 +74,3 @@
.channelTeaser { .channelTeaser {
color: $brand-grey; color: $brand-grey;
} }
.channelResults {
display: grid;
grid-template-columns: 1fr;
grid-gap: $spacer;
@media (min-width: $break-point--small) {
grid-template-columns: 1fr 1fr;
}
}

View File

@ -3,7 +3,7 @@ import { render } from '@testing-library/react'
import ChannelTeaser from './ChannelTeaser' import ChannelTeaser from './ChannelTeaser'
import { BrowserRouter } from 'react-router-dom' import { BrowserRouter } from 'react-router-dom'
import { User } from '../../context' import { User } from '../../context'
import { userMockConnected } from '../../../__mocks__/user-mock' import { userMockConnected } from '../../__mocks__/user-mock'
describe('ChannelTeaser', () => { describe('ChannelTeaser', () => {
it('renders without crashing', () => { it('renders without crashing', () => {

View File

@ -1,19 +1,18 @@
import React, { Component } from 'react' import React, { Component } from 'react'
import { Link } from 'react-router-dom' import { Link } from 'react-router-dom'
import { User } from '../../context' import { User } from '../../context'
import { Logger } from '@oceanprotocol/squid' import { Logger, DDO } from '@oceanprotocol/squid'
import Spinner from '../atoms/Spinner' import CategoryImage from '../atoms/CategoryImage'
import AssetTeaser from '../molecules/AssetTeaser' import SearchResults from '../molecules/SearchResults'
import styles from './ChannelTeaser.module.scss' import styles from './ChannelTeaser.module.scss'
import channels from '../../data/channels.json' import channels from '../../data/channels.json'
import CategoryImage from '../atoms/CategoryImage'
interface ChannelTeaserProps { interface ChannelTeaserProps {
channel: string channel: string
} }
interface ChannelTeaserState { interface ChannelTeaserState {
channelAssets?: any[] channelAssets?: DDO[]
isLoadingChannel?: boolean isLoadingChannel?: boolean
} }
@ -81,17 +80,11 @@ export default class ChannelTeaser extends Component<
</header> </header>
</div> </div>
<div> <div>
{isLoadingChannel ? ( <SearchResults
<Spinner message="Loading..." /> isLoading={isLoadingChannel}
) : channelAssets && channelAssets.length ? ( results={channelAssets}
<div className={styles.channelResults}> simpleGrid
{channelAssets.map((asset: any) => ( />
<AssetTeaser key={asset.id} asset={asset} />
))}
</div>
) : (
<div>No data sets found.</div>
)}
</div> </div>
</div> </div>
) )

View File

@ -3,8 +3,8 @@ import { render, fireEvent } from '@testing-library/react'
import ReactModal from 'react-modal' import ReactModal from 'react-modal'
import WalletSelector from './WalletSelector' import WalletSelector from './WalletSelector'
import { User, Market } from '../../context' import { User, Market } from '../../context'
import { userMockConnected } from '../../../__mocks__/user-mock' import { userMockConnected } from '../../__mocks__/user-mock'
import { marketMock } from '../../../__mocks__/market-mock' import { marketMock } from '../../__mocks__/market-mock'
describe('WalletSelector', () => { describe('WalletSelector', () => {
it('renders without crashing', () => { it('renders without crashing', () => {

View File

@ -90,7 +90,7 @@ export default class WalletSelector extends PureComponent<
title={content.title} title={content.title}
description={content.description} description={content.description}
isOpen={this.state.isModalOpen} isOpen={this.state.isModalOpen}
toggleModal={this.handleToggleModal} onToggleModal={this.handleToggleModal}
> >
<div className={styles.info}> <div className={styles.info}>
{content.buttons.map(({ title, description, icon }) => ( {content.buttons.map(({ title, description, icon }) => (

View File

@ -2,8 +2,8 @@ import React from 'react'
import { render } from '@testing-library/react' import { render } from '@testing-library/react'
import Web3message from './Web3message' import Web3message from './Web3message'
import { User, Market } from '../../context' import { User, Market } from '../../context'
import { userMock, userMockConnected } from '../../../__mocks__/user-mock' import { userMock, userMockConnected } from '../../__mocks__/user-mock'
import { marketMock } from '../../../__mocks__/market-mock' import { marketMock } from '../../__mocks__/market-mock'
describe('Web3message', () => { describe('Web3message', () => {
it('renders with burner wallet message', () => { it('renders with burner wallet message', () => {

View File

@ -7,8 +7,8 @@ import { StateMock } from '@react-mock/state'
import ReactGA from 'react-ga' import ReactGA from 'react-ga'
import { User, Market } from '../../../context' import { User, Market } from '../../../context'
import AssetFile, { messages } from './AssetFile' import AssetFile, { messages } from './AssetFile'
import { userMockConnected } from '../../../../__mocks__/user-mock' import { userMockConnected } from '../../../__mocks__/user-mock'
import { marketMock } from '../../../../__mocks__/market-mock' import { marketMock } from '../../../__mocks__/market-mock'
const file = { const file = {
index: 0, index: 0,

View File

@ -36,13 +36,13 @@ export default class Report extends PureComponent<
this.signal.cancel() this.signal.cancel()
} }
private inputChange = (event: ChangeEvent<HTMLInputElement>) => { private handleInputChange = (event: ChangeEvent<HTMLInputElement>) => {
this.setState({ this.setState({
comment: event.target.value comment: event.target.value
}) })
} }
private toggleModal = () => { private handleToggleModal = () => {
this.setState({ isModalOpen: !this.state.isModalOpen }) this.setState({ isModalOpen: !this.state.isModalOpen })
this.state.isModalOpen && this.reset() this.state.isModalOpen && this.reset()
} }
@ -100,7 +100,7 @@ export default class Report extends PureComponent<
<Button <Button
link link
className={styles.openLink} className={styles.openLink}
onClick={this.toggleModal} onClick={this.handleToggleModal}
> >
Report Data Set Report Data Set
</Button> </Button>
@ -108,7 +108,7 @@ export default class Report extends PureComponent<
title="Report Data Set" title="Report Data Set"
description="Found some faulty metadata, wrongly attributed data, or anything else wrong with this data set? Tell us about it and we will take a look." description="Found some faulty metadata, wrongly attributed data, or anything else wrong with this data set? Tell us about it and we will take a look."
isOpen={this.state.isModalOpen} isOpen={this.state.isModalOpen}
toggleModal={this.toggleModal} onToggleModal={this.handleToggleModal}
> >
<div className={styles.info}> <div className={styles.info}>
<h3>{this.props.title}</h3> <h3>{this.props.title}</h3>
@ -135,7 +135,7 @@ export default class Report extends PureComponent<
help="Briefly describe what is wrong with this asset. If you want to get contacted by us, add your email at the end." help="Briefly describe what is wrong with this asset. If you want to get contacted by us, add your email at the end."
required required
value={this.state.comment} value={this.state.comment}
onChange={this.inputChange} onChange={this.handleInputChange}
rows={1} rows={1}
/> />
<Button <Button

View File

@ -1,21 +1 @@
@import '../../styles/variables'; @import '../../styles/variables';
.results {
display: grid;
grid-template-columns: 1fr;
grid-gap: $spacer;
max-width: calc(18rem + #{$spacer * 2});
margin: auto;
margin-top: $spacer * 2;
@media (min-width: $break-point--small) {
margin-left: 0;
margin-right: 0;
max-width: none;
grid-template-columns: repeat(2, 1fr);
}
@media (min-width: $break-point--medium) {
grid-template-columns: repeat(3, 1fr);
}
}

View File

@ -3,7 +3,7 @@ import { render } from '@testing-library/react'
import Channel from './Channel' import Channel from './Channel'
import { User } from '../../context' import { User } from '../../context'
import { createMemoryHistory } from 'history' import { createMemoryHistory } from 'history'
import { userMockConnected } from '../../../__mocks__/user-mock' import { userMockConnected } from '../../__mocks__/user-mock'
import { MemoryRouter } from 'react-router' import { MemoryRouter } from 'react-router'
describe('Channel', () => { describe('Channel', () => {

View File

@ -1,12 +1,10 @@
import React, { PureComponent } from 'react' import React, { PureComponent } from 'react'
import { Logger } from '@oceanprotocol/squid' import { Logger } from '@oceanprotocol/squid'
import { History } from 'history' import { History } from 'history'
import Spinner from '../../components/atoms/Spinner'
import Route from '../../components/templates/Route' import Route from '../../components/templates/Route'
import { User } from '../../context' import { User } from '../../context'
import AssetTeaser from '../molecules/AssetTeaser'
import Pagination from '../../components/molecules/Pagination' import Pagination from '../../components/molecules/Pagination'
import styles from './Channel.module.scss' import SearchResults, { SearchResultsState } from '../molecules/SearchResults'
import Content from '../../components/atoms/Content' import Content from '../../components/atoms/Content'
import channels from '../../data/channels.json' import channels from '../../data/channels.json'
import CategoryImage from '../atoms/CategoryImage' import CategoryImage from '../atoms/CategoryImage'
@ -20,13 +18,7 @@ interface ChannelProps {
} }
} }
interface ChannelState { interface ChannelState extends SearchResultsState {
results: any[]
totalResults: number
offset: number
totalPages: number
currentPage: number
isLoading: boolean
title: string title: string
description: string description: string
} }
@ -81,31 +73,28 @@ export default class Channel extends PureComponent<ChannelProps, ChannelState> {
} }
} }
private handlePageClick = async (data: { selected: number }) => { private onPageClick = async (data: { selected: number }) => {
// react-pagination starts counting at 0, we start at 1 // react-pagination starts counting at 0, we start at 1
const toPage = data.selected + 1 const toPage = data.selected + 1
this.props.history.push({ search: `?page=${toPage}` }) this.props.history.push({ search: `?page=${toPage}` })
await this.setState({ currentPage: toPage, isLoading: true }) this.setState({
currentPage: toPage,
isLoading: true
})
await this.getChannelAssets() await this.getChannelAssets()
} }
public renderResults = () =>
this.state.isLoading ? (
<Spinner message="Searching..." />
) : this.state.results && this.state.results.length ? (
<div className={styles.results}>
{this.state.results.map((asset: any) => (
<AssetTeaser key={asset.id} asset={asset} />
))}
</div>
) : (
<div>No data sets found.</div>
)
public render() { public render() {
const { title, description, totalPages, currentPage } = this.state const {
title,
description,
totalPages,
currentPage,
isLoading,
results
} = this.state
return ( return (
<Route <Route
@ -114,12 +103,12 @@ export default class Channel extends PureComponent<ChannelProps, ChannelState> {
image={<CategoryImage header category={title} />} image={<CategoryImage header category={title} />}
> >
<Content wide> <Content wide>
{this.renderResults()} <SearchResults isLoading={isLoading} results={results} />
<Pagination <Pagination
totalPages={totalPages} totalPages={totalPages}
currentPage={currentPage} currentPage={currentPage}
handlePageClick={this.handlePageClick} handlePageClick={this.onPageClick}
/> />
</Content> </Content>
</Route> </Route>

View File

@ -2,7 +2,7 @@ import React from 'react'
import { render } from '@testing-library/react' import { render } from '@testing-library/react'
import MarketProvider from './MarketProvider' import MarketProvider from './MarketProvider'
import { User, Market } from '../context' import { User, Market } from '../context'
import { userMockConnected } from '../../__mocks__/user-mock' import { userMockConnected } from '../__mocks__/user-mock'
describe('MarketProvider', () => { describe('MarketProvider', () => {
it('renders without crashing', () => { it('renders without crashing', () => {

View File

@ -4,7 +4,7 @@ import { createMemoryHistory, createLocation } from 'history'
import { render } from '@testing-library/react' import { render } from '@testing-library/react'
import Channels from './Channels' import Channels from './Channels'
import { User } from '../context' import { User } from '../context'
import { userMockConnected } from '../../__mocks__/user-mock' import { userMockConnected } from '../__mocks__/user-mock'
const history = createMemoryHistory() const history = createMemoryHistory()
const location = createLocation('/channels') const location = createLocation('/channels')

View File

@ -4,7 +4,7 @@ import { MemoryRouter } from 'react-router'
import { createMemoryHistory, createLocation } from 'history' import { createMemoryHistory, createLocation } from 'history'
import Faucet from '.' import Faucet from '.'
import { User, Market } from '../../context' import { User, Market } from '../../context'
import { userMockConnected } from '../../../__mocks__/user-mock' import { userMockConnected } from '../../__mocks__/user-mock'
const history = createMemoryHistory() const history = createMemoryHistory()
const location = createLocation('/faucet') const location = createLocation('/faucet')

View File

@ -16,7 +16,7 @@ export default class Search extends PureComponent<SearchProps, SearchState> {
search: '' search: ''
} }
private inputChange = (event: ChangeEvent<HTMLInputElement>) => { private handleInputChange = (event: ChangeEvent<HTMLInputElement>) => {
this.setState({ this.setState({
search: event.target.value search: event.target.value
}) })
@ -38,7 +38,7 @@ export default class Search extends PureComponent<SearchProps, SearchState> {
label="Search for data sets" label="Search for data sets"
placeholder="e.g. shapes of plants" placeholder="e.g. shapes of plants"
value={search} value={search}
onChange={this.inputChange} onChange={this.handleInputChange}
group={ group={
<Button primary disabled={!search}> <Button primary disabled={!search}>
Search Search

View File

@ -3,7 +3,7 @@ import { Router } from 'react-router'
import { createMemoryHistory, createLocation } from 'history' import { createMemoryHistory, createLocation } from 'history'
import { render } from '@testing-library/react' import { render } from '@testing-library/react'
import Home from '.' import Home from '.'
import { userMock } from '../../../__mocks__/user-mock' import { userMock } from '../../__mocks__/user-mock'
import { User } from '../../context' import { User } from '../../context'
const history = createMemoryHistory() const history = createMemoryHistory()

View File

@ -45,7 +45,7 @@ export default class ItemForm extends PureComponent<
this.props.addFile(url) this.props.addFile(url)
} }
private onChangeUrl = (e: React.FormEvent<HTMLInputElement>) => { private handleChangeUrl = (e: React.FormEvent<HTMLInputElement>) => {
this.setState({ url: e.currentTarget.value }) this.setState({ url: e.currentTarget.value })
this.clearErrors() this.clearErrors()
} }
@ -67,7 +67,7 @@ export default class ItemForm extends PureComponent<
type="url" type="url"
placeholder={this.props.placeholder} placeholder={this.props.placeholder}
value={url} value={url}
onChange={this.onChangeUrl} onChange={this.handleChangeUrl}
help="Supported protocols are http(s):// and ipfs://" help="Supported protocols are http(s):// and ipfs://"
/> />

View File

@ -46,7 +46,6 @@ describe('Files', () => {
it('renders without crashing', () => { it('renders without crashing', () => {
const { container } = render(ui) const { container } = render(ui)
expect(container.firstChild).toBeInTheDocument() expect(container.firstChild).toBeInTheDocument()
expect(container.querySelector('.itemForm')).not.toBeInTheDocument() expect(container.querySelector('.itemForm')).not.toBeInTheDocument()
}) })
@ -82,21 +81,21 @@ describe('Files', () => {
}) })
it('item can be removed', () => { it('item can be removed', () => {
const { getByTitle } = render(ui) const { getAllByTitle } = render(ui)
fireEvent.click(getAllByTitle('Remove item')[0])
fireEvent.click(getByTitle('Remove item'))
expect(files.length).toBe(0) expect(files.length).toBe(0)
}) })
it('item can be added', async () => { it('item can be added', async () => {
const { getByText, getByPlaceholderText } = render(ui) const { getAllByText, getByText, getByPlaceholderText } = render(ui)
fireEvent.click(getByText('+ From URL')) fireEvent.click(getAllByText('+ From URL')[0])
await waitForElement(() => getByText('- Cancel')) await waitForElement(() => getByText('- Cancel'))
fireEvent.change(getByPlaceholderText('Hello'), { fireEvent.change(getByPlaceholderText('Hello'), {
target: { value: 'https://hello.com' } target: { value: 'https://hello.com' }
}) })
fireEvent.click(getByText('Add File')) fireEvent.click(getByText('Add File'))
mockAxios.mockResponse(mockResponse) mockAxios.mockResponse(mockResponse)
expect(mockAxios).toHaveBeenCalled() expect(mockAxios).toHaveBeenCalled()
}) })

View File

@ -4,7 +4,7 @@ import { render, fireEvent } from '@testing-library/react'
import { createMemoryHistory, createLocation } from 'history' import { createMemoryHistory, createLocation } from 'history'
import Publish from '.' import Publish from '.'
import { User } from '../../context' import { User } from '../../context'
import { userMockConnected } from '../../../__mocks__/user-mock' import { userMockConnected } from '../../__mocks__/user-mock'
const history = createMemoryHistory() const history = createMemoryHistory()
const location = createLocation('/publish') const location = createLocation('/publish')

View File

@ -256,7 +256,7 @@ class Publish extends Component<{}, PublishState> {
} }
} }
private registerAsset = async (event: FormEvent<HTMLFormElement>) => { private handleRegisterAsset = async (event: FormEvent<HTMLFormElement>) => {
event.preventDefault() event.preventDefault()
ReactGA.event({ category: 'Publish', action: 'registerAsset-start' }) ReactGA.event({ category: 'Publish', action: 'registerAsset-start' })
@ -348,7 +348,7 @@ class Publish extends Component<{}, PublishState> {
currentStep={this.state.currentStep} currentStep={this.state.currentStep}
/> />
<Form onSubmit={this.registerAsset}> <Form onSubmit={this.handleRegisterAsset}>
{steps.map((step: any, index: number) => ( {steps.map((step: any, index: number) => (
<Step <Step
key={index} key={index}

View File

@ -10,23 +10,3 @@
color: $brand-grey-dark; color: $brand-grey-dark;
} }
} }
.results {
display: grid;
grid-template-columns: 1fr;
grid-gap: $spacer;
@media (min-width: $break-point--small) {
grid-template-columns: repeat(2, 1fr);
}
@media (min-width: $break-point--medium) {
grid-template-columns: repeat(3, 1fr);
}
}
.empty {
text-align: center;
margin-top: $spacer * 4;
color: $brand-grey-light;
}

View File

@ -4,7 +4,7 @@ import Search from './Search'
import { User } from '../context' import { User } from '../context'
import { createMemoryHistory } from 'history' import { createMemoryHistory } from 'history'
import { BrowserRouter as Router } from 'react-router-dom' import { BrowserRouter as Router } from 'react-router-dom'
import { userMockConnected } from '../../__mocks__/user-mock' import { userMockConnected } from '../__mocks__/user-mock'
const history = createMemoryHistory() const history = createMemoryHistory()

View File

@ -1,12 +1,12 @@
import React, { PureComponent } from 'react' import React, { PureComponent } from 'react'
import { Link } from 'react-router-dom'
import queryString from 'query-string' import queryString from 'query-string'
import { History, Location } from 'history' import { History, Location } from 'history'
import { Logger } from '@oceanprotocol/squid' import { Logger } from '@oceanprotocol/squid'
import Spinner from '../components/atoms/Spinner' import SearchResults, {
SearchResultsState
} from '../components/molecules/SearchResults'
import Route from '../components/templates/Route' import Route from '../components/templates/Route'
import { User } from '../context' import { User } from '../context'
import AssetTeaser from '../components/molecules/AssetTeaser'
import Pagination from '../components/molecules/Pagination' import Pagination from '../components/molecules/Pagination'
import styles from './Search.module.scss' import styles from './Search.module.scss'
import Content from '../components/atoms/Content' import Content from '../components/atoms/Content'
@ -17,13 +17,7 @@ interface SearchProps {
history: History history: History
} }
interface SearchState { interface SearchState extends SearchResultsState {
results: any[]
totalResults: number
offset: number
totalPages: number
currentPage: number
isLoading: boolean
searchTerm: string searchTerm: string
searchCategories: string searchCategories: string
} }
@ -103,7 +97,7 @@ class Search extends PureComponent<SearchProps, SearchState> {
} }
} }
private handlePageClick = async (data: { selected: number }) => { private onPageClick = async (data: { selected: number }) => {
// react-pagination starts counting at 0, we start at 1 // react-pagination starts counting at 0, we start at 1
const toPage = data.selected + 1 const toPage = data.selected + 1
@ -112,49 +106,41 @@ class Search extends PureComponent<SearchProps, SearchState> {
search: `?text=${this.state.searchTerm}&page=${toPage}` search: `?text=${this.state.searchTerm}&page=${toPage}`
}) })
await this.setState({ currentPage: toPage, isLoading: true }) this.setState({ currentPage: toPage, isLoading: true })
await this.searchAssets() await this.searchAssets()
} }
public renderResults = () =>
this.state.isLoading ? (
<Spinner message="Searching..." />
) : this.state.results && this.state.results.length ? (
<div className={styles.results}>
{this.state.results.map((asset: any) => (
<AssetTeaser key={asset.id} asset={asset} />
))}
</div>
) : (
<div className={styles.empty}>
<p>No Data Sets Found.</p>
<Link to="/publish">+ Publish A Data Set</Link>
</div>
)
public render() { public render() {
const { totalResults, totalPages, currentPage } = this.state const {
totalResults,
totalPages,
currentPage,
isLoading,
results,
searchTerm,
searchCategories
} = this.state
return ( return (
<Route title="Search" wide> <Route title="Search" wide>
<Content wide> <Content wide>
{!this.state.isLoading && ( {!isLoading && (
<h2 className={styles.resultsTitle}> <h2 className={styles.resultsTitle}>
{totalResults} results for{' '} {totalResults} results for{' '}
<span> <span>
{decodeURIComponent( {decodeURIComponent(
this.state.searchTerm || searchTerm || searchCategories
this.state.searchCategories
)} )}
</span> </span>
</h2> </h2>
)} )}
{this.renderResults()}
<SearchResults isLoading={isLoading} results={results} />
<Pagination <Pagination
totalPages={totalPages} totalPages={totalPages}
currentPage={currentPage} currentPage={currentPage}
handlePageClick={this.handlePageClick} handlePageClick={this.onPageClick}
/> />
</Content> </Content>
</Route> </Route>

View File

@ -7,11 +7,11 @@
"dependencies": [ "dependencies": [
{ {
"name": "keeper-contracts", "name": "keeper-contracts",
"version": "~0.12.7" "version": "~0.13.2"
}, },
{ {
"name": "brizo", "name": "brizo",
"version": "~0.7.2" "version": "~0.8.1"
}, },
{ {
"name": "aquarius", "name": "aquarius",
@ -19,7 +19,7 @@
}, },
{ {
"name": "squid-js", "name": "squid-js",
"version": "~1.0.0" "version": "~1.1.0"
}, },
{ {
"name": "faucet", "name": "faucet",

3883
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
{ {
"name": "commons", "name": "commons",
"description": "Ocean Protocol marketplace to explore, download, and publish open data sets.", "description": "Ocean Protocol marketplace to explore, download, and publish open data sets.",
"version": "2.0.1", "version": "2.2.0",
"license": "Apache-2.0", "license": "Apache-2.0",
"scripts": { "scripts": {
"install": "./scripts/install.sh", "install": "./scripts/install.sh",
@ -25,26 +25,26 @@
"dependencies": {}, "dependencies": {},
"devDependencies": { "devDependencies": {
"@release-it/bumper": "^1.0.5", "@release-it/bumper": "^1.0.5",
"@typescript-eslint/eslint-plugin": "^1.6.0", "@typescript-eslint/eslint-plugin": "^2.18.0",
"@typescript-eslint/parser": "^1.6.0", "@typescript-eslint/parser": "^2.18.0",
"auto-changelog": "^1.16.2", "auto-changelog": "^1.16.2",
"concurrently": "^5.0.0", "concurrently": "^5.1.0",
"cypress": "^3.7.0", "cypress": "^3.8.3",
"cypress-log-to-output": "^1.0.7", "cypress-log-to-output": "^1.0.7",
"eslint": "^5.16.0", "eslint": "^6.8.0",
"eslint-config-oceanprotocol": "^1.4.0", "eslint-config-oceanprotocol": "^1.5.0",
"eslint-config-prettier": "^6.5.0", "eslint-config-prettier": "^6.10.0",
"eslint-plugin-cypress": "^2.7.0", "eslint-plugin-cypress": "^2.8.1",
"eslint-plugin-prettier": "^3.1.1", "eslint-plugin-prettier": "^3.1.2",
"prettier": "^1.19.1", "prettier": "^1.19.1",
"prettier-stylelint": "^0.4.2", "prettier-stylelint": "^0.4.2",
"release-it": "^12.4.3", "release-it": "^12.4.3",
"start-server-and-test": "^1.10.6", "start-server-and-test": "^1.10.8",
"stylelint": "^12.0.0", "stylelint": "^13.0.0",
"stylelint-config-bigchaindb": "^1.2.2", "stylelint-config-bigchaindb": "^1.2.2",
"stylelint-config-css-modules": "^2.1.0", "stylelint-config-css-modules": "^2.2.0",
"stylelint-config-standard": "^19.0.0", "stylelint-config-standard": "^19.0.0",
"typescript": "^3.7.3" "typescript": "^3.7.5"
}, },
"repository": { "repository": {
"type": "git", "type": "git",

746
server/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
{ {
"name": "commons-server", "name": "commons-server",
"description": "Ocean Protocol marketplace backend.", "description": "Ocean Protocol marketplace backend.",
"version": "2.0.1", "version": "2.2.0",
"license": "Apache-2.0", "license": "Apache-2.0",
"main": "dist/src/server.js", "main": "dist/src/server.js",
"scripts": { "scripts": {
@ -13,13 +13,13 @@
"coverage": "cat coverage/lcov.info | codacy-coverage --token 8801f827fe1144ffa85cd7da94f2bbf7" "coverage": "cat coverage/lcov.info | codacy-coverage --token 8801f827fe1144ffa85cd7da94f2bbf7"
}, },
"dependencies": { "dependencies": {
"@sendgrid/mail": "^6.4.0", "@sendgrid/mail": "^6.5.1",
"body-parser": "^1.18.3", "body-parser": "^1.18.3",
"compression": "^1.7.4", "compression": "^1.7.4",
"debug": "^4.1.1", "debug": "^4.1.1",
"dotenv": "^8.2.0", "dotenv": "^8.2.0",
"express": "^4.17.1", "express": "^4.17.1",
"express-validator": "^6.3.0", "express-validator": "^6.3.1",
"morgan": "^1.9.1", "morgan": "^1.9.1",
"request": "^2.88.0" "request": "^2.88.0"
}, },
@ -28,17 +28,17 @@
"@types/compression": "^1.0.1", "@types/compression": "^1.0.1",
"@types/debug": "^4.1.5", "@types/debug": "^4.1.5",
"@types/express": "^4.17.2", "@types/express": "^4.17.2",
"@types/jest": "^24.0.23", "@types/jest": "^24.9.1",
"@types/morgan": "^1.7.37", "@types/morgan": "^1.7.37",
"@types/node": "^12.12.14", "@types/node": "^13.5.3",
"@types/request": "^2.48.3", "@types/request": "^2.48.4",
"@types/supertest": "^2.0.8", "@types/supertest": "^2.0.8",
"jest": "^24.9.0", "jest": "24.9.0",
"nodemon": "^2.0.1", "nodemon": "^2.0.2",
"supertest": "^4.0.2", "supertest": "^4.0.2",
"ts-jest": "^24.2.0", "ts-jest": "24.3.0",
"ts-node": "^8.5.4", "ts-node": "^8.6.2",
"typescript": "^3.7.3" "typescript": "^3.7.5"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
@ -46,6 +46,10 @@
}, },
"jest": { "jest": {
"preset": "ts-jest", "preset": "ts-jest",
"testPathIgnorePatterns": [
"/node_modules/",
"/dist/"
],
"collectCoverageFrom": [ "collectCoverageFrom": [
"src/**/*.{ts,tsx}" "src/**/*.{ts,tsx}"
] ]

View File

@ -2,7 +2,7 @@ import 'dotenv/config'
const config = { const config = {
app: { port: 4000 }, app: { port: 4000 },
sendgridApiKey: process.env.SENDGRID_API_KEY, sendgridApiKey: process.env.SENDGRID_API_KEY || '',
ipfsGatewayUri: process.env.IPFS_GATEWAY_URI || 'https://gateway.ipfs.io' ipfsGatewayUri: process.env.IPFS_GATEWAY_URI || 'https://gateway.ipfs.io'
} }

View File

@ -1,5 +1,6 @@
{ {
"compilerOptions": { "compilerOptions": {
"strict": true,
"module": "commonjs", "module": "commonjs",
"esModuleInterop": true, "esModuleInterop": true,
"resolveJsonModule": true, "resolveJsonModule": true,