From 8023e30061e679d67a2b0813f47ae0d9d9b2caef Mon Sep 17 00:00:00 2001 From: Max Berman Date: Mon, 16 Dec 2019 11:44:14 +0100 Subject: [PATCH] init network switcher component --- .eslintrc | 84 +++-- .prettierrc | 5 +- .vscode/settings.json | 3 + client/src/App.tsx | 47 +-- .../components/molecules/NetworkSwitcher.tsx | 12 + .../molecules/VersionNumbers/VersionTable.tsx | 173 +++++---- client/src/config.ts | 57 ++- client/src/index.tsx | 1 + client/src/ocean.ts | 75 ++-- client/src/routes/Publish/Files/index.tsx | 340 +++++++++--------- 10 files changed, 423 insertions(+), 374 deletions(-) create mode 100644 .vscode/settings.json create mode 100644 client/src/components/molecules/NetworkSwitcher.tsx diff --git a/.eslintrc b/.eslintrc index 7e01e46..c0bcdd1 100644 --- a/.eslintrc +++ b/.eslintrc @@ -1,43 +1,49 @@ { - "parser": "@typescript-eslint/parser", - "parserOptions": { - "project": [ - "./tsconfig.json", - "./client/tsconfig.json", - "./server/tsconfig.json", - "./cypress/tsconfig.json" - ] - }, - "extends": [ - "oceanprotocol", - "oceanprotocol/react", - "plugin:@typescript-eslint/eslint-recommended", - "plugin:@typescript-eslint/recommended", - "plugin:prettier/recommended", - "prettier/react", - "prettier/standard", - "prettier/@typescript-eslint", - "plugin:cypress/recommended" + "parser": "@typescript-eslint/parser", + "parserOptions": { + "project": [ + "./tsconfig.json", + "./client/tsconfig.json", + "./server/tsconfig.json", + "./cypress/tsconfig.json" + ] + }, + "extends": [ + "oceanprotocol", + "oceanprotocol/react", + "plugin:@typescript-eslint/eslint-recommended", + "plugin:@typescript-eslint/recommended", + "plugin:prettier/recommended", + "prettier/react", + "prettier/standard", + "prettier/@typescript-eslint", + "plugin:cypress/recommended" + ], + "plugins": ["@typescript-eslint", "prettier", "cypress"], + "rules": { + "@typescript-eslint/explicit-function-return-type": 0, + "@typescript-eslint/member-delimiter-style": [ + "error", + { "multiline": { "delimiter": "none" } } ], - "plugins": ["@typescript-eslint", "prettier", "cypress"], - "rules": { - "@typescript-eslint/explicit-function-return-type": 0, - "@typescript-eslint/member-delimiter-style": [ - "error", - { "multiline": { "delimiter": "none" } } - ], - "@typescript-eslint/no-explicit-any": "off" - }, - "env": { - "es6": true, - "browser": true, - "node": true, - "jest": true, - "cypress/globals": true - }, - "settings": { - "react": { - "version": "16.10" - } + "@typescript-eslint/no-explicit-any": "off", + "react/no-unescaped-entities": 0, + "react/self-closing-comp": 0, + "react/void-dom-elements-no-children": 0, + "react/jsx-indent": 0, + "react/jsx-indent-props": 0, + "react/jsx-max-props-per-line": 0 + }, + "env": { + "es6": true, + "browser": true, + "node": true, + "jest": true, + "cypress/globals": true + }, + "settings": { + "react": { + "version": "16.10" } + } } diff --git a/.prettierrc b/.prettierrc index c522042..96fdb0b 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,5 +1,6 @@ { "semi": false, "singleQuote": true, - "trailingComma": "none" -} \ No newline at end of file + "trailingComma": "none", + "tabWidth": 2 +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..55712c1 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "typescript.tsdk": "node_modules/typescript/lib" +} \ No newline at end of file diff --git a/client/src/App.tsx b/client/src/App.tsx index 6fb1692..cb4d578 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -5,33 +5,36 @@ import Footer from './components/organisms/Footer' import Spinner from './components/atoms/Spinner' import { User } from './context' import Routes from './Routes' +import {commonsNetwork} from './components/molecules/NetworkSwitcher' import './styles/global.scss' import styles from './App.module.scss' +console.log(commonsNetwork) + export default class App extends Component { - public render() { - return ( -
- - <> -
+ public render() { + return ( +
+ + <> +
-
- {this.context.isLoading ? ( -
- -
- ) : ( - - )} -
- -
- - -
- ) - } +
+ {this.context.isLoading ? ( +
+ +
+ ) : ( + + )} +
+
+ + +
+ ) + } } + App.contextType = User diff --git a/client/src/components/molecules/NetworkSwitcher.tsx b/client/src/components/molecules/NetworkSwitcher.tsx new file mode 100644 index 0000000..02af907 --- /dev/null +++ b/client/src/components/molecules/NetworkSwitcher.tsx @@ -0,0 +1,12 @@ +import { CONNECTIONS } from '../../config' + +/* TEMP NETWORK SWITCHER */ + +const urlParams = new URLSearchParams(window.location.search) +const network = urlParams.get('network') || 'pacific' +const idx = Object.keys(CONNECTIONS).indexOf(network) +const commonsNetwork = Object.values(CONNECTIONS)[idx] + + + +export { commonsNetwork } \ No newline at end of file diff --git a/client/src/components/molecules/VersionNumbers/VersionTable.tsx b/client/src/components/molecules/VersionNumbers/VersionTable.tsx index d568d25..62f4bce 100644 --- a/client/src/components/molecules/VersionNumbers/VersionTable.tsx +++ b/client/src/components/molecules/VersionNumbers/VersionTable.tsx @@ -3,110 +3,109 @@ import { VersionNumbersState } from '.' import VersionTableRow from './VersionTableRow' import styles from './VersionTable.module.scss' import VersionNumber from './VersionNumber' +import { useParams } from 'react-router-dom' import { - serviceUri, - nodeUri, - aquariusUri, - brizoUri, - brizoAddress, - secretStoreUri, - faucetUri + serviceUri, + nodeUri, + aquariusUri, + brizoUri, + brizoAddress, + secretStoreUri, + faucetUri, + CONNECTIONS } from '../../../config' + const commonsConfig = { - serviceUri, - nodeUri, - aquariusUri, - brizoUri, - brizoAddress, - secretStoreUri, - faucetUri + serviceUri, + nodeUri, + aquariusUri, + brizoUri, + brizoAddress, + secretStoreUri, + faucetUri } export const VersionTableContracts = ({ - contracts, - network, - keeperVersion + contracts, + network, + keeperVersion }: { - contracts: { - [contractName: string]: string - } - network: string - keeperVersion?: string + contracts: { + [contractName: string]: string + } + network: string + keeperVersion?: string }) => ( - - - - - - - {contracts && - Object.keys(contracts) - // sort alphabetically - .sort((a, b) => a.localeCompare(b)) - .map(key => { - const submarineLink = `https://submarine.${ - network === 'pacific' - ? 'oceanprotocol' - : `${network}.dev-ocean` - }.com/address/${contracts[key]}` +
- Keeper Contracts - - -
+ + + + + + {contracts && + Object.keys(contracts) + // sort alphabetically + .sort((a, b) => a.localeCompare(b)) + .map(key => { + const submarineLink = `https://submarine.${ + network === 'pacific' ? 'oceanprotocol' : `${network}.dev-ocean` + }.com/address/${contracts[key]}` - return ( - - - - - ) - })} - -
+ Keeper Contracts + + +
- {key} - - - {contracts[key]} - -
+ return ( + + + + {key} + + + + {contracts[key]} + + + + ) + })} + + ) export const VersionTableCommons = () => ( - - - {Object.entries(commonsConfig).map(([key, value]) => ( - - - - - ))} - -
- {key} - - {value} -
+ + + {Object.entries(commonsConfig).map(([key, value]) => ( + + + + + ))} + +
+ {key} + + {value} +
) const VersionTable = ({ data }: { data: VersionNumbersState }) => { - return ( -
- - - {Object.entries(data) - .filter(([key]) => key !== 'status') - .map(([key, value]) => ( - - ))} - -
-
- ) + return ( +
+ + + {Object.entries(data) + .filter(([key]) => key !== 'status') + .map(([key, value]) => ( + + ))} + +
+
+ ) } export default VersionTable diff --git a/client/src/config.ts b/client/src/config.ts index 2d5cb5b..53be7e1 100644 --- a/client/src/config.ts +++ b/client/src/config.ts @@ -2,26 +2,26 @@ // commons-server connection // export const serviceUri = - process.env.REACT_APP_SERVICE_URI || 'http://localhost:4000' + process.env.REACT_APP_SERVICE_URI || 'http://localhost:4000' // // OCEAN REMOTE CONNECTIONS // export const nodeUri = - process.env.REACT_APP_NODE_URI || 'https://pacific.oceanprotocol.com' + process.env.REACT_APP_NODE_URI || 'https://pacific.oceanprotocol.com' export const aquariusUri = - process.env.REACT_APP_AQUARIUS_URI || - 'https://aquarius.commons.oceanprotocol.com' + process.env.REACT_APP_AQUARIUS_URI || + 'https://aquarius.commons.oceanprotocol.com' export const brizoUri = - process.env.REACT_APP_BRIZO_URI || 'https://brizo.commons.oceanprotocol.com' + process.env.REACT_APP_BRIZO_URI || 'https://brizo.commons.oceanprotocol.com' export const brizoAddress = - process.env.REACT_APP_BRIZO_ADDRESS || - '0x008c25ed3594e094db4592f4115d5fa74c4f41ea' + process.env.REACT_APP_BRIZO_ADDRESS || + '0x008c25ed3594e094db4592f4115d5fa74c4f41ea' export const secretStoreUri = - process.env.REACT_APP_SECRET_STORE_URI || - 'https://secret-store.oceanprotocol.com' + process.env.REACT_APP_SECRET_STORE_URI || + 'https://secret-store.oceanprotocol.com' export const faucetUri = - process.env.REACT_APP_FAUCET_URI || 'https://faucet.oceanprotocol.com' + process.env.REACT_APP_FAUCET_URI || 'https://faucet.oceanprotocol.com' // // APP CONFIG @@ -30,13 +30,40 @@ export const verbose = true export const analyticsId = 'UA-60614729-11' export const showChannels = - process.env.REACT_APP_SHOW_CHANNELS === 'true' || false + process.env.REACT_APP_SHOW_CHANNELS === 'true' || false export const allowPricing = - process.env.REACT_APP_ALLOW_PRICING === 'true' || false + process.env.REACT_APP_ALLOW_PRICING === 'true' || false export const showRequestTokens = - process.env.REACT_APP_SHOW_REQUEST_TOKENS_BUTTON === 'true' || false + process.env.REACT_APP_SHOW_REQUEST_TOKENS_BUTTON === 'true' || false // https://ipfs.github.io/public-gateway-checker/ export const ipfsGatewayUri = - process.env.REACT_APP_IPFS_GATEWAY_URI || 'https://gateway.ipfs.io' + process.env.REACT_APP_IPFS_GATEWAY_URI || 'https://gateway.ipfs.io' export const ipfsNodeUri = - process.env.REACT_APP_IPFS_NODE_URI || 'https://ipfs.infura.io:5001' + process.env.REACT_APP_IPFS_NODE_URI || 'https://ipfs.infura.io:5001' + +export const CONNECTIONS = { + pacific: { + nodeUri: 'https://pacific.oceanprotocol.com', + aquariusUri: 'https://aquarius.commons.oceanprotocol.com', + brizoUri: 'https://brizo.commons.oceanprotocol.com', + brizoAddress: '0x008c25ed3594e094db4592f4115d5fa74c4f41ea', + secretStoreUri: 'https://secret-store.oceanprotocol.com', + faucetUri: 'https://faucet.oceanprotocol.com' + }, + nile: { + nodeUri: 'https://nile.dev-ocean.com', + aquariusUri: 'https://aquarius.nile.dev-ocean.com', + brizoUri: 'https://brizo.nile.dev-ocean.com', + brizoAddress: '0x4aaab179035dc57b35e2ce066919048686f82972', + secretStoreUri: 'https://secret-store.nile.dev-ocean.com', + faucetUri: 'https://faucet.nile.dev-ocean.com' + }, + duero: { + nodeUri: 'https://duero.dev-ocean.com', + aquariusUri: 'https://aquarius.duero.dev-ocean.com', + brizoUri: 'https://brizo.duero.dev-ocean.com', + brizoAddress: '0x9d4ed58293f71122ad6a733c1603927a150735d0', + secretStoreUri: 'https://secret-store.duero.dev-ocean.com', + faucetUri: 'https://faucet.duero.dev-ocean.com' + } +} diff --git a/client/src/index.tsx b/client/src/index.tsx index 54596d0..6f156e1 100644 --- a/client/src/index.tsx +++ b/client/src/index.tsx @@ -21,6 +21,7 @@ export { renderToDOM } renderToDOM() + // If you want your app to work offline and load faster, you can change // unregister() to register() below. Note this comes with some pitfalls. // Learn more about service workers: http://bit.ly/CRA-PWA diff --git a/client/src/ocean.ts b/client/src/ocean.ts index d0511b2..d26b4d2 100644 --- a/client/src/ocean.ts +++ b/client/src/ocean.ts @@ -1,55 +1,58 @@ import { Ocean, Logger } from '@oceanprotocol/squid' import Web3 from 'web3' +import { User } from './context' import { + aquariusUri, + brizoUri, + brizoAddress, + faucetUri, + nodeUri, + secretStoreUri, + verbose +} from './config' + + + +export async function provideOcean(web3Provider: Web3) { + const config = { + web3Provider, + nodeUri, aquariusUri, brizoUri, brizoAddress, - faucetUri, - nodeUri, secretStoreUri, verbose -} from './config' - -export async function provideOcean(web3Provider: Web3) { - const config = { - web3Provider, - nodeUri, - aquariusUri, - brizoUri, - brizoAddress, - secretStoreUri, - verbose - } - const ocean: any = await Ocean.getInstance(config) - return { ocean } + } + const ocean: any = await Ocean.getInstance(config) + return { ocean } } // // Faucet // export interface FaucetResponse { - success: boolean - message: string - trxHash?: string + success: boolean + message: string + trxHash?: string } export async function requestFromFaucet(account: string) { - try { - const url = `${faucetUri}/faucet` - const response = await fetch(url, { - method: 'POST', - headers: { - Accept: 'application/json', - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ - address: account, - agent: 'commons' - }) - }) - return response.json() - } catch (error) { - Logger.error('requestFromFaucet', error.message) - } + try { + const url = `${faucetUri}/faucet` + const response = await fetch(url, { + method: 'POST', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + address: account, + agent: 'commons' + }) + }) + return response.json() + } catch (error) { + Logger.error('requestFromFaucet', error.message) + } } diff --git a/client/src/routes/Publish/Files/index.tsx b/client/src/routes/Publish/Files/index.tsx index e6002a4..e180ee0 100644 --- a/client/src/routes/Publish/Files/index.tsx +++ b/client/src/routes/Publish/Files/index.tsx @@ -1,9 +1,9 @@ import React, { - lazy, - Suspense, - FormEvent, - PureComponent, - ChangeEvent + lazy, + Suspense, + FormEvent, + PureComponent, + ChangeEvent } from 'react' import axios from 'axios' import { Logger, File } from '@oceanprotocol/squid' @@ -21,202 +21,196 @@ import Spinner from '../../../components/atoms/Spinner' const Ipfs = lazy(() => import('./Ipfs')) export interface FilePublish extends File { - found: boolean // non-standard + found: boolean // non-standard } interface FilesProps { - files: File[] - placeholder: string - help?: string - name: string - onChange( - event: - | ChangeEvent - | FormEvent - | ChangeEvent - | ChangeEvent - ): void + files: File[] + placeholder: string + help?: string + name: string + onChange( + event: + | ChangeEvent + | FormEvent + | ChangeEvent + | ChangeEvent + ): void } interface FilesStates { - isFormShown: boolean - isIpfsFormShown: boolean + isFormShown: boolean + isIpfsFormShown: boolean } const buttons = [ - { - id: 'url', - title: '+ From URL', - titleActive: '- Cancel' - }, - { - id: 'ipfs', - title: '+ Add to IPFS', - titleActive: '- Cancel' - } + { + id: 'url', + title: '+ From URL', + titleActive: '- Cancel' + }, + { + id: 'ipfs', + title: '+ Add to IPFS', + titleActive: '- Cancel' + } ] export default class Files extends PureComponent { - public state: FilesStates = { + public state: FilesStates = { + isFormShown: false, + isIpfsFormShown: false + } + + // for canceling axios requests + public signal = axios.CancelToken.source() + + public componentWillUnmount() { + this.signal.cancel() + } + + private toggleForm = (e: Event, form: string) => { + e.preventDefault() + + this.setState({ + isFormShown: form === 'url' ? !this.state.isFormShown : false, + isIpfsFormShown: form === 'ipfs' ? !this.state.isIpfsFormShown : false + }) + } + + private async getFile(url: string) { + const file: FilePublish = { + url, + contentType: '', + found: false // non-standard + } + + try { + const response = await axios({ + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + url: `${serviceUri}/api/v1/urlcheck`, + data: { url }, + cancelToken: this.signal.token + }) + + const { contentLength, contentType, found } = response.data.result + + if (contentLength) file.contentLength = contentLength + if (contentType) { + file.contentType = contentType + file.compression = cleanupContentType(contentType) + } + + file.found = found + + return file + } catch (error) { + !axios.isCancel(error) && Logger.error(error.message) + } + } + + private addFile = async (url: string) => { + // check for duplicate urls + const duplicateFiles = this.props.files.filter(props => + url.includes(props.url) + ) + + if (duplicateFiles.length > 0) { + return this.setState({ isFormShown: false, isIpfsFormShown: false + }) } - // for canceling axios requests - public signal = axios.CancelToken.source() + const file: FilePublish | undefined = await this.getFile(url) + file && this.props.files.push(file) - public componentWillUnmount() { - this.signal.cancel() + const event = { + currentTarget: { + name: 'files', + value: this.props.files + } } + this.props.onChange(event as any) - private toggleForm = (e: Event, form: string) => { - e.preventDefault() + this.setState({ + isFormShown: false, + isIpfsFormShown: false + }) - this.setState({ - isFormShown: form === 'url' ? !this.state.isFormShown : false, - isIpfsFormShown: - form === 'ipfs' ? !this.state.isIpfsFormShown : false - }) + this.forceUpdate() + } + + private removeFile = (index: number) => { + this.props.files.splice(index, 1) + const event = { + currentTarget: { + name: 'files', + value: this.props.files + } } + this.props.onChange(event as any) + this.forceUpdate() + } - private async getFile(url: string) { - const file: FilePublish = { - url, - contentType: '', - found: false // non-standard - } + public render() { + const { files, help, placeholder, name, onChange } = this.props + const { isFormShown, isIpfsFormShown } = this.state - try { - const response = await axios({ - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - url: `${serviceUri}/api/v1/urlcheck`, - data: { url }, - cancelToken: this.signal.token - }) + return ( + <> + {help && {help}} - const { contentLength, contentType, found } = response.data.result + {/* Use hidden input to collect files */} + - if (contentLength) file.contentLength = contentLength - if (contentType) { - file.contentType = contentType - file.compression = cleanupContentType(contentType) - } - - file.found = found - - return file - } catch (error) { - !axios.isCancel(error) && Logger.error(error.message) - } - } - - private addFile = async (url: string) => { - // check for duplicate urls - const duplicateFiles = this.props.files.filter(props => - url.includes(props.url) - ) - - if (duplicateFiles.length > 0) { - return this.setState({ - isFormShown: false, - isIpfsFormShown: false - }) - } - - const file: FilePublish | undefined = await this.getFile(url) - file && this.props.files.push(file) - - const event = { - currentTarget: { - name: 'files', - value: this.props.files - } - } - this.props.onChange(event as any) - - this.setState({ - isFormShown: false, - isIpfsFormShown: false - }) - - this.forceUpdate() - } - - private removeFile = (index: number) => { - this.props.files.splice(index, 1) - const event = { - currentTarget: { - name: 'files', - value: this.props.files - } - } - this.props.onChange(event as any) - this.forceUpdate() - } - - public render() { - const { files, help, placeholder, name, onChange } = this.props - const { isFormShown, isIpfsFormShown } = this.state - - return ( - <> - {help && {help}} - - {/* Use hidden input to collect files */} - + {files.length > 0 && ( +
    + {files.map((item: any, index: number) => ( + this.removeFile(index)} /> + ))} +
+ )} -
- {files.length > 0 && ( -
    - {files.map((item: any, index: number) => ( - this.removeFile(index)} - /> - ))} -
- )} + {buttons.map(button => { + const isActive = + (button.id === 'url' && isFormShown) || + (button.id === 'ipfs' && isIpfsFormShown) - {buttons.map(button => { - const isActive = - (button.id === 'url' && isFormShown) || - (button.id === 'ipfs' && isIpfsFormShown) + return ( + + ) + })} - return ( - - ) - })} + {isFormShown && ( + + )} - {isFormShown && ( - - )} - - {isIpfsFormShown && ( - }> - - - )} -
- - ) - } + {isIpfsFormShown && ( + }> + + + )} + + + ) + } }