1
0
mirror of https://github.com/oceanprotocol/market.git synced 2024-11-15 09:44:53 +01:00

Merge pull request #68 from oceanprotocol/feature/history

History page
This commit is contained in:
Matthias Kretschmann 2020-10-01 17:34:15 +02:00 committed by GitHub
commit c460904903
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
38 changed files with 4605 additions and 7650 deletions

11078
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -11,7 +11,7 @@
"jest": "NODE_ENV=test jest -c tests/unit/jest.config.js", "jest": "NODE_ENV=test jest -c tests/unit/jest.config.js",
"test": "npm run lint && npm run jest", "test": "npm run lint && npm run jest",
"test:watch": "npm run lint && npm run jest -- --watch", "test:watch": "npm run lint && npm run jest -- --watch",
"lint": "eslint --ignore-path .gitignore --ext .js --ext .ts --ext .tsx .", "lint": "eslint --ignore-path .gitignore --ext .js --ext .ts --ext .tsx . && npm run type-check",
"format": "prettier --ignore-path .gitignore './**/*.{css,yml,js,ts,tsx,json}' --write", "format": "prettier --ignore-path .gitignore './**/*.{css,yml,js,ts,tsx,json}' --write",
"type-check": "tsc --noEmit", "type-check": "tsc --noEmit",
"analyze": "npm run build && source-map-explorer 'public/*.js'", "analyze": "npm run build && source-map-explorer 'public/*.js'",
@ -22,8 +22,8 @@
"@coingecko/cryptoformat": "^0.4.2", "@coingecko/cryptoformat": "^0.4.2",
"@loadable/component": "5.13.1", "@loadable/component": "5.13.1",
"@oceanprotocol/art": "^3.0.0", "@oceanprotocol/art": "^3.0.0",
"@oceanprotocol/lib": "^0.3.2", "@oceanprotocol/lib": "^0.5.2",
"@oceanprotocol/react": "^0.0.48", "@oceanprotocol/react": "^0.0.50",
"@oceanprotocol/typographies": "^0.1.0", "@oceanprotocol/typographies": "^0.1.0",
"@sindresorhus/slugify": "^1.0.0", "@sindresorhus/slugify": "^1.0.0",
"@tippyjs/react": "^4.2.0", "@tippyjs/react": "^4.2.0",
@ -38,19 +38,19 @@
"dotenv": "^8.2.0", "dotenv": "^8.2.0",
"ethereum-blockies": "github:MyEtherWallet/blockies", "ethereum-blockies": "github:MyEtherWallet/blockies",
"filesize": "^6.1.0", "filesize": "^6.1.0",
"formik": "^2.1.5", "formik": "^2.1.6",
"gatsby": "^2.24.66", "gatsby": "^2.24.67",
"gatsby-image": "^2.4.20", "gatsby-image": "^2.4.20",
"gatsby-plugin-manifest": "^2.4.32", "gatsby-plugin-manifest": "^2.4.33",
"gatsby-plugin-react-helmet": "^3.3.12", "gatsby-plugin-react-helmet": "^3.3.12",
"gatsby-plugin-remove-trailing-slashes": "^2.3.13", "gatsby-plugin-remove-trailing-slashes": "^2.3.13",
"gatsby-plugin-sharp": "^2.6.37", "gatsby-plugin-sharp": "^2.6.38",
"gatsby-plugin-svgr": "^2.0.2", "gatsby-plugin-svgr": "^2.0.2",
"gatsby-plugin-webpack-size": "^1.0.0", "gatsby-plugin-webpack-size": "^1.0.0",
"gatsby-source-filesystem": "^2.3.31", "gatsby-source-filesystem": "^2.3.32",
"gatsby-source-graphql": "^2.7.5", "gatsby-source-graphql": "^2.7.5",
"gatsby-transformer-json": "^2.4.13", "gatsby-transformer-json": "^2.4.13",
"gatsby-transformer-remark": "^2.8.36", "gatsby-transformer-remark": "^2.8.37",
"gatsby-transformer-sharp": "^2.5.16", "gatsby-transformer-sharp": "^2.5.16",
"intersection-observer": "^0.11.0", "intersection-observer": "^0.11.0",
"is-url-superb": "^4.0.0", "is-url-superb": "^4.0.0",

View File

@ -1,25 +0,0 @@
import React, { ReactElement } from 'react'
import Eye from '../../../images/eye.svg'
import Button from '../Button'
import Tooltip from '../Tooltip'
import { ComputeItem } from '@oceanprotocol/react'
export declare type ActionsCellProps = {
handleOnClickViewJobDetails?: (computeItem: ComputeItem) => void
}
export default function ActionsCell({
handleOnClickViewJobDetails
}: ActionsCellProps): ReactElement {
return (
<>
{handleOnClickViewJobDetails && (
<Tooltip content="View job details">
<Button onClick={handleOnClickViewJobDetails}>
<Eye />
</Button>
</Tooltip>
)}
</>
)
}

View File

@ -1,6 +0,0 @@
import React from 'react'
import Time from '../Time'
export default function DateCell({ date }: { date: any }) {
return date && <Time date={date} />
}

View File

@ -1,6 +0,0 @@
import React from 'react'
import { Link } from 'gatsby'
export default function DdoLinkCell({ id, name }: { id: any; name: any }) {
return <Link to={`/asset/${id}`}>{name}</Link>
}

View File

@ -1,35 +0,0 @@
import React, { ReactElement } from 'react'
import DataTable from 'react-data-table-component'
export declare type AssetTablePagination = {
count: number
rowsPerPage: number
page: number
handleChangePage: (
event: React.MouseEvent<HTMLButtonElement> | null,
page: number
) => void
handleChangeRowsPerPage: React.ChangeEventHandler<
HTMLTextAreaElement | HTMLInputElement
>
}
export default function Table({
columns,
data,
pagination
}: {
columns: any
data: any
pagination?: AssetTablePagination
}): ReactElement {
return (
<div>
{data?.length ? (
<DataTable noHeader columns={columns} data={data} />
) : (
<div>No Data Sets Yet.</div>
)}
</div>
)
}

View File

@ -1,7 +1,7 @@
import React from 'react' import React from 'react'
import { Link } from 'gatsby' import { Link } from 'gatsby'
import Dotdotdot from 'react-dotdotdot' import Dotdotdot from 'react-dotdotdot'
import { MetadataMarket } from '../../@types/Metadata' import { MetadataMarket } from '../../@types/MetaData'
import Price from '../atoms/Price' import Price from '../atoms/Price'
import styles from './AssetTeaser.module.css' import styles from './AssetTeaser.module.css'
import { DDO } from '@oceanprotocol/lib' import { DDO } from '@oceanprotocol/lib'

View File

@ -1,76 +0,0 @@
import React, { useState, useEffect, ReactElement } from 'react'
import { useNavigate } from '@reach/router'
import { DDO } from '@oceanprotocol/lib'
import Button from '../atoms/Button'
import BaseDialog from '../atoms/BaseDialog'
import { useOcean } from '@oceanprotocol/react'
const content = [
'You are about to delete your Data Set.',
'Your Data Set is being deleted...',
'You have deleted your Data Set ',
'Something happened... Your Data Set cannot be deleted'
]
export default function DeleteAction({ ddo }: { ddo: DDO }): ReactElement {
const { ocean, accountId } = useOcean()
const navigate = useNavigate()
const isOwner = ddo.publicKey[0].owner === accountId
const [isModal, setIsModal] = useState(false)
const [status, setStatus] = useState(0) // 0-confirmation, 1-deleting, 2-success, 3-error
const { attributes } = ddo.findServiceByType('metadata')
useEffect(() => {
let tId: number
if (status === 2) {
tId = window.setTimeout(() => {
navigate(`/`)
}, 1000)
}
return () => {
clearTimeout(tId)
}
}, [status])
if (!accountId || !ocean || !isOwner) return null
async function handleDeleteAction() {
if (!ocean) return
setStatus(1)
setIsModal(true)
try {
const consumerAddress = (await ocean.accounts.list())[0]
await ocean.assets.retire(ddo.id, consumerAddress)
setStatus(2)
} catch (error) {
// TODO: handle error
console.log(error)
setStatus(3)
}
}
const handleCancel = () => {
setIsModal(false)
setStatus(0)
}
const handleOpenConfirmation = () => setIsModal(true)
return (
<>
<Button onClick={handleOpenConfirmation}>Delete</Button>
<BaseDialog
title={`Delete ${attributes.main.name}`}
open={isModal}
onClose={() => setIsModal(false)}
>
{content[status]}
<footer>
<Button onClick={handleDeleteAction}>Confirm</Button>
<Button onClick={handleCancel}>Cancel</Button>
</footer>
</BaseDialog>
</>
)
}

View File

@ -1,16 +1,16 @@
import React, { ReactElement, useState, useEffect } from 'react'
import stylesIndex from './index.module.css'
import styles from './Dynamic.module.css'
import FormHelp from '../../../atoms/Input/Help'
import Wallet from '../../Wallet'
import { DataTokenOptions, useOcean } from '@oceanprotocol/react' import { DataTokenOptions, useOcean } from '@oceanprotocol/react'
import Alert from '../../../atoms/Alert' import React, { ReactElement, useEffect, useState } from 'react'
import Coin from './Coin'
import { isCorrectNetwork } from '../../../../utils/wallet'
import { useSiteMetadata } from '../../../../hooks/useSiteMetadata'
import Tooltip from '../../../atoms/Tooltip'
import Fees from './Fees'
import { PriceOptionsMarket } from '../../../../@types/MetaData' import { PriceOptionsMarket } from '../../../../@types/MetaData'
import { useSiteMetadata } from '../../../../hooks/useSiteMetadata'
import { isCorrectNetwork } from '../../../../utils/wallet'
import Alert from '../../../atoms/Alert'
import FormHelp from '../../../atoms/Input/Help'
import Tooltip from '../../../atoms/Tooltip'
import Wallet from '../../Wallet'
import Coin from './Coin'
import styles from './Dynamic.module.css'
import Fees from './Fees'
import stylesIndex from './index.module.css'
export default function Dynamic({ export default function Dynamic({
ocean, ocean,

View File

@ -1,14 +0,0 @@
.metaGrid {
border-radius: var(--border-radius);
display: grid;
gap: calc(var(--spacer) / 2);
grid-template-columns: 1fr 1fr;
}
.metaRow {
padding-top: calc(var(--spacer) / 2);
border-radius: var(--border-radius);
display: grid;
gap: calc(var(--spacer) / 2);
grid-template-columns: auto;
}

View File

@ -1,67 +0,0 @@
import React, { ReactElement } from 'react'
import { ComputeItem } from '@oceanprotocol/react'
import BaseDialog from '../atoms/BaseDialog'
import styles from './JobDetailsDialog.module.css'
import MetaItem from '../organisms/AssetContent/MetaItem'
import Time from '../atoms/Time'
import shortid from 'shortid'
import { Link } from 'gatsby'
export default function JobDetailsDialog({
computeItem,
isOpen,
onClose
}: {
computeItem: ComputeItem | undefined
isOpen: boolean
onClose: () => void
}): ReactElement {
if (!computeItem) return null
const { attributes } = computeItem.ddo.findServiceByType('metadata')
const { name } = attributes.main
const {
dateCreated,
dateFinished,
statusText,
jobId,
resultsUrls,
algorithmLogUrl
} = computeItem.job
return (
<BaseDialog title={name} open={isOpen} onClose={onClose}>
<div className={styles.metaGrid}>
<MetaItem title="Date Created" content={<Time date={dateCreated} />} />
<MetaItem title="Status" content={statusText} />
<MetaItem
title="Date Finished"
content={<Time date={dateFinished} />}
/>
<MetaItem title="Job Id" content={jobId} />
</div>
<div className={styles.metaRow}>
{resultsUrls && (
<MetaItem
title="Results"
content={resultsUrls.map((url: string) => (
<Link to={url} key={shortid.generate()}>
{url}
</Link>
))}
/>
)}
{algorithmLogUrl && (
<MetaItem
title="Algorithm Log"
content={<Link to={algorithmLogUrl}>{algorithmLogUrl}</Link>}
/>
)}
<MetaItem
title="Data Set"
content={<Link to={`/asset/${computeItem.ddo.id}`}>{name}</Link>}
/>
</div>
</BaseDialog>
)
}

View File

@ -57,23 +57,14 @@ export default function Pool({ ddo }: { ddo: DDO }): ReactElement {
// //
// Get data token symbol // Get data token symbol
// //
const dtSymbol = await ocean.datatokens.getSymbol( const dtSymbol = await ocean.datatokens.getSymbol(ddo.dataToken)
ddo.dataToken,
accountId
)
setDtSymbol(dtSymbol) setDtSymbol(dtSymbol)
// //
// Get everything which is in the pool // Get everything which is in the pool
// //
const oceanReserve = await ocean.pool.getOceanReserve( const oceanReserve = await ocean.pool.getOceanReserve(price.address)
accountId, const dtReserve = await ocean.pool.getDTReserve(price.address)
price.address
)
const dtReserve = await ocean.pool.getDTReserve(
accountId,
price.address
)
setTotalBalance({ setTotalBalance({
ocean: oceanReserve, ocean: oceanReserve,
dt: dtReserve dt: dtReserve
@ -106,7 +97,7 @@ export default function Pool({ ddo }: { ddo: DDO }): ReactElement {
setUserBalance(userBalance) setUserBalance(userBalance)
// Get liquidity provider fee // Get liquidity provider fee
const swapFee = await ocean.pool.getSwapFee(accountId, price.address) const swapFee = await ocean.pool.getSwapFee(price.address)
setSwapFee(swapFee) setSwapFee(swapFee)
} catch (error) { } catch (error) {
console.error(error.message) console.error(error.message)

View File

@ -2,7 +2,7 @@ import React, { ReactElement, useEffect, useState } from 'react'
import Time from '../../atoms/Time' import Time from '../../atoms/Time'
import MetaItem from './MetaItem' import MetaItem from './MetaItem'
import styles from './MetaFull.module.css' import styles from './MetaFull.module.css'
import { MetadataMarket } from '../../../@types/Metadata' import { MetadataMarket } from '../../../@types/MetaData'
import { DDO } from '@oceanprotocol/lib' import { DDO } from '@oceanprotocol/lib'
import EtherscanLink from '../../atoms/EtherscanLink' import EtherscanLink from '../../atoms/EtherscanLink'
@ -15,7 +15,7 @@ export default function MetaFull({
ddo: DDO ddo: DDO
metadata: MetadataMarket metadata: MetadataMarket
}): ReactElement { }): ReactElement {
const { ocean, accountId } = useOcean() const { ocean } = useOcean()
const { id, dataToken } = ddo const { id, dataToken } = ddo
const { dateCreated, datePublished, author, license } = metadata.main const { dateCreated, datePublished, author, license } = metadata.main
@ -26,13 +26,13 @@ export default function MetaFull({
if (!ocean) return if (!ocean) return
async function getDataTokenInfo() { async function getDataTokenInfo() {
const name = await ocean.datatokens.getName(dataToken, accountId) const name = await ocean.datatokens.getName(dataToken)
setDtName(name) setDtName(name)
const symbol = await ocean.datatokens.getSymbol(dataToken, accountId) const symbol = await ocean.datatokens.getSymbol(dataToken)
setDtSymbol(symbol) setDtSymbol(symbol)
} }
getDataTokenInfo() getDataTokenInfo()
}, [ocean, accountId, dataToken]) }, [ocean, dataToken])
return ( return (
<div className={styles.metaFull}> <div className={styles.metaFull}>

View File

@ -1,7 +1,7 @@
import React, { ReactElement } from 'react' import React, { ReactElement } from 'react'
import MetaItem from './MetaItem' import MetaItem from './MetaItem'
import styles from './MetaSecondary.module.css' import styles from './MetaSecondary.module.css'
import { MetadataMarket } from '../../../@types/Metadata' import { MetadataMarket } from '../../../@types/MetaData'
import Tags from '../../atoms/Tags' import Tags from '../../atoms/Tags'
import Button from '../../atoms/Button' import Button from '../../atoms/Button'

View File

@ -1,4 +1,4 @@
import { MetadataMarket } from '../../../@types/Metadata' import { MetadataMarket } from '../../../@types/MetaData'
import React, { ReactElement } from 'react' import React, { ReactElement } from 'react'
import Time from '../../atoms/Time' import Time from '../../atoms/Time'
import { Link } from 'gatsby' import { Link } from 'gatsby'

View File

@ -5,7 +5,7 @@ import { useLocation, useNavigate } from '@reach/router'
import Pagination from '../molecules/Pagination' import Pagination from '../molecules/Pagination'
import { updateQueryStringParameter } from '../../utils' import { updateQueryStringParameter } from '../../utils'
import styles from './AssetList.module.css' import styles from './AssetList.module.css'
import { MetadataMarket } from '../../@types/Metadata' import { MetadataMarket } from '../../@types/MetaData'
import { DDO } from '@oceanprotocol/lib' import { DDO } from '@oceanprotocol/lib'
import { useOcean } from '@oceanprotocol/react' import { useOcean } from '@oceanprotocol/react'

View File

@ -1,81 +0,0 @@
import React, { useEffect, useState, ReactElement } from 'react'
import Loader from '../atoms/Loader'
import {
useOcean,
OceanConnectionStatus,
useSearch
} from '@oceanprotocol/react'
import Table from '../atoms/Table'
import Price from '../atoms/Price'
import { fromWei } from 'web3-utils'
import DateCell from '../atoms/Table/DateCell'
import DdoLinkCell from '../atoms/Table/DdoLinkCell'
import { MetadataMain } from '@oceanprotocol/lib'
const consumedColumns = [
{
name: 'Published',
selector: 'published',
sortable: true,
cell: function getCell(row: any) {
return <DateCell date={row.published} />
}
},
{
name: 'Name',
selector: 'name',
sortable: true,
cell: function getCell(row: any) {
return <DdoLinkCell id={row.id} name={row.name} />
}
},
{
name: 'Price',
selector: 'price',
sortable: true,
cell: function getCell(row: any) {
return <Price price={fromWei(row.price)} small />
}
}
]
export default function ConsumedList(): ReactElement {
const { ocean, status, accountId, account } = useOcean()
const [consumedList, setConsumedList] = useState<any>([])
const { getConsumedList } = useSearch()
const [isLoading, setIsLoading] = useState(false)
useEffect(() => {
async function getConsumed() {
if (!accountId || !ocean || status !== OceanConnectionStatus.CONNECTED)
return
setIsLoading(true)
const consumedItems = await getConsumedList()
if (!consumedItems) return
const data = consumedItems.map((ddo) => {
const { attributes } = ddo.findServiceByType('metadata')
const { name, price, datePublished } = attributes.main as MetadataMain
return {
published: datePublished,
name: name,
price: price
}
})
setConsumedList(data)
setIsLoading(false)
}
getConsumed()
}, [accountId, ocean, status])
return isLoading ? (
<Loader />
) : account && ocean ? (
<Table data={consumedList} columns={consumedColumns} />
) : (
<div>Connect your wallet to see your consumed data sets.</div>
)
}

View File

@ -1,144 +0,0 @@
import React, { useState, ReactElement } from 'react'
import Loader from '../atoms/Loader'
import {
useOcean,
OceanConnectionStatus,
useSearch,
ComputeItem
} from '@oceanprotocol/react'
import Price from '../atoms/Price'
import { fromWei } from 'web3-utils'
import Table from '../atoms/Table'
import Button from '../atoms/Button'
import { MetadataMain, Logger } from '@oceanprotocol/lib'
import DateCell from '../atoms/Table/DateCell'
import DdoLinkCell from '../atoms/Table/DdoLinkCell'
import shortid from 'shortid'
import ActionsCell from '../atoms/Table/ActionsCell'
import JobDetailsDialog from '../molecules/JobDetailsDialog'
const columns = [
{
name: 'Created',
selector: 'dateCreated',
sortable: true,
cell: function getCell(row: any) {
return <DateCell date={row.dateCreated} />
}
},
{
name: 'Finished',
selector: 'dateFinished',
sortable: true,
cell: function getCell(row: any) {
return <DateCell date={row.dateFinished} />
}
},
{
name: 'Name',
selector: 'name',
sortable: true,
cell: function getCell(row: any) {
return <DdoLinkCell id={row.id} name={row.name} />
}
},
{
name: 'Price',
selector: 'price',
sortable: true,
cell: function getCell(row: any) {
return <Price price={fromWei(row.price)} small />
}
},
{
name: 'Status',
selector: 'status'
},
{
name: 'Actions',
selector: 'actions',
cell: function getCell(row: any) {
return (
<ActionsCell handleOnClickViewJobDetails={row.onClickViewJobDetails} />
)
}
}
]
export default function JobsList(): ReactElement {
const { ocean, status, accountId } = useOcean()
const [jobList, setJobList] = useState<any[]>([])
const [isLoading, setIsLoading] = useState(false)
const [userAgreed, setUserAgreed] = useState(false)
const { getComputeItems } = useSearch()
const [isOpen, setIsOpen] = useState(false)
const [detailsComputeItem, setDetailsComputeItem] = useState<ComputeItem>()
const onClickViewJobDetails = (compute: ComputeItem) => {
setDetailsComputeItem(compute)
setIsOpen(true)
}
const dialogClose = () => {
setIsOpen(false)
}
const getJobs = async () => {
if (!accountId || !ocean || status !== OceanConnectionStatus.CONNECTED)
return
setIsLoading(true)
setUserAgreed(true)
try {
const computeItems = await getComputeItems()
if (!computeItems) return
const data = computeItems.map((item) => {
const { attributes } = item.ddo.findServiceByType('metadata')
const { name, price } = attributes.main as MetadataMain
return {
dateCreated: item.job.dateCreated,
dateFinished: item.job.dateFinished,
status: item.job.statusText,
name: name,
price: price,
did: item.ddo.id,
id: shortid.generate(),
onClickViewJobDetails: () => onClickViewJobDetails(item)
}
})
setJobList(data)
setIsLoading(false)
} catch (err) {
Logger.error(err)
// TODO: no error handling
} finally {
setIsLoading(false)
}
}
return isLoading ? (
<Loader />
) : accountId && ocean ? (
userAgreed ? (
<>
<JobDetailsDialog
computeItem={detailsComputeItem}
isOpen={isOpen}
onClose={dialogClose}
/>
<Table data={jobList} columns={columns} />
</>
) : (
<>
<div>
<Button style="primary" onClick={getJobs}>
Sign to retrieve jobs
</Button>
</div>
</>
)
) : (
<div>Connect your wallet to see your compute jobs.</div>
)
}

View File

@ -1,97 +0,0 @@
import React, { useEffect, useState, ReactElement } from 'react'
import Loader from '../atoms/Loader'
import { MetadataMain } from '@oceanprotocol/lib'
import {
useOcean,
OceanConnectionStatus,
useSearch
} from '@oceanprotocol/react'
import Table from '../atoms/Table'
import Price from '../atoms/Price'
import { fromWei } from 'web3-utils'
import DateCell from '../atoms/Table/DateCell'
import DdoLinkCell from '../atoms/Table/DdoLinkCell'
const publishedColumns = [
{
name: 'Published',
selector: 'published',
sortable: true,
cell: function getCell(row: any) {
return <DateCell date={row.published} />
}
},
{
name: 'Name',
selector: 'name',
sortable: true,
cell: function getCell(row: any) {
return <DdoLinkCell id={row.id} name={row.name} />
}
},
{
name: 'Price',
selector: 'price',
sortable: true,
cell: function getCell(row: any) {
return <Price price={fromWei(row.price)} small />
}
}
]
export default function PublishedList(): ReactElement {
const { ocean, status, account, accountId } = useOcean()
const { getPublishedList } = useSearch()
const [publishedList, setPublishedList] = useState<any[]>([])
const [isLoading, setIsLoading] = useState(false)
const [paginationParams, setPaginationParams] = useState({
count: 1,
rowsPerPage: 10,
page: 1
})
useEffect(() => {
async function getPublished() {
if (
!account ||
!accountId ||
!ocean ||
status !== OceanConnectionStatus.CONNECTED
)
return
setIsLoading(true)
const publishedItems = await getPublishedList(
paginationParams.page,
paginationParams.rowsPerPage
)
setPaginationParams({
...paginationParams,
count: publishedItems.totalPages
})
const data = publishedItems.results.map((ddo) => {
const { attributes } = ddo.findServiceByType('metadata')
const { name, price, datePublished } = attributes.main as MetadataMain
return {
published: datePublished,
name: name,
price: price,
id: ddo.id
}
})
setPublishedList(data)
setIsLoading(false)
}
getPublished()
}, [accountId, ocean, status])
return isLoading ? (
<Loader />
) : account && ocean ? (
<Table data={publishedList} columns={publishedColumns} />
) : (
<div>Connect your wallet to see your published data sets.</div>
)
}

View File

@ -1,51 +0,0 @@
import React from 'react'
import styles from './History.module.css'
import Web3Feedback from '../molecules/Wallet/Feedback'
import ConsumedList from '../organisms/ConsumedList'
import PublishedList from '../organisms/PublishedList'
import JobsList from '../organisms/JobsList'
const sections = [
{
title: 'Published',
component: 'Coming Soon...'
},
{
title: 'Downloaded',
component: 'Coming Soon...'
},
{
title: 'Compute Jobs',
component: 'Coming Soon...'
}
]
const Section = ({ title, component }: { title: string; component: any }) => {
return (
<div className={styles.section}>
<h2 className={styles.sectionTitle}>{title}</h2>
{component}
</div>
)
}
const HistoryPage: React.FC = () => {
return (
<article className={styles.grid}>
<div className={styles.content}>
{sections.map((section) => {
const { title, component } = section
return <Section key={title} title={title} component={component} />
})}
</div>
<aside>
<div className={styles.sticky}>
<Web3Feedback />
</div>
</aside>
</article>
)
}
export default HistoryPage

View File

@ -0,0 +1,15 @@
.table div {
background-color: transparent !important;
}
.table [role='columnheader'] {
font-weight: var(--font-weight-bold);
}
.empty {
width: 100%;
text-align: left;
color: var(--color-secondary);
font-size: var(--font-size-small);
font-style: italic;
}

View File

@ -0,0 +1,79 @@
import { PoolTransaction } from '@oceanprotocol/lib/dist/node/balancer/OceanPool'
import { useMetadata, useOcean } from '@oceanprotocol/react'
import { Link } from 'gatsby'
import React, { ReactElement, useEffect, useState } from 'react'
import DataTable from 'react-data-table-component'
import EtherscanLink from '../../atoms/EtherscanLink'
import Time from '../../atoms/Time'
import styles from './PoolTransactions.module.css'
function AssetTitle({ did }: { did: string }): ReactElement {
const { title } = useMetadata(did)
return <Link to={`/asset/${did}`}>{title || did}</Link>
}
function Empty() {
return <div className={styles.empty}>No results found</div>
}
const columns = [
{
name: 'Title',
selector: function getTitleRow(row: PoolTransaction) {
// TODO: replace hardcoded symbol with symbol fetching based
// on row.tonenIn & row.tokenOut
const title = row.tokenAmountIn
? `Add ${row.tokenAmountIn} OCEAN`
: `Remove ${row.tokenAmountOut} OCEAN`
return (
<EtherscanLink network="rinkeby" path={`/tx/${row.transactionHash}`}>
{title}
</EtherscanLink>
)
}
},
{
name: 'Data Set',
selector: function getAssetRow(row: PoolTransaction) {
const did = row.dtAddress.replace('0x', 'did:op:')
return <AssetTitle did={did} />
}
},
{
name: 'Time',
selector: function getTimeRow(row: PoolTransaction) {
return (
<Time date={new Date(row.timestamp * 1000).toUTCString()} relative />
)
}
}
]
export default function PoolTransactions(): ReactElement {
const { ocean, accountId } = useOcean()
const [logs, setLogs] = useState<PoolTransaction[]>()
useEffect(() => {
async function getLogs() {
if (!ocean || !accountId) return
const logs = await ocean.pool.getAllPoolLogs(accountId)
// limit to 100 latest transactions for now
setLogs(logs.slice(0, 99))
}
getLogs()
}, [ocean, accountId])
return (
<DataTable
columns={columns}
data={logs}
className={styles.table}
noHeader
pagination={logs?.length >= 19}
paginationPerPage={20}
noDataComponent={<Empty />}
/>
)
}

View File

@ -0,0 +1,38 @@
import { Logger } from '@oceanprotocol/lib'
import { QueryResult } from '@oceanprotocol/lib/dist/node/metadatastore/MetadataStore'
import { useOcean } from '@oceanprotocol/react'
import React, { ReactElement, useEffect, useState } from 'react'
import Loader from '../../atoms/Loader'
import AssetList from '../../organisms/AssetList'
export default function PublishedList(): ReactElement {
const { ocean, status, accountId } = useOcean()
// TODO: wait for ocean-lib-js with https://github.com/oceanprotocol/ocean-lib-js/pull/308
const [queryResult, setQueryResult] = useState<QueryResult>()
const [isLoading, setIsLoading] = useState(false)
useEffect(() => {
async function getPublished() {
if (!accountId || !ocean) return
try {
setIsLoading(true)
const queryResult = await ocean.assets.ownerAssets(accountId)
setQueryResult(queryResult)
} catch (error) {
Logger.error(error.message)
} finally {
setIsLoading(false)
}
}
getPublished()
}, [ocean, status, accountId])
return isLoading ? (
<Loader />
) : accountId && ocean ? (
<AssetList queryResult={queryResult} />
) : (
<div>Connect your wallet to see your published data sets.</div>
)
}

View File

@ -17,6 +17,18 @@
} }
.content { .content {
composes: box from '../atoms/Box.module.css';
margin-top: var(--spacer); margin-top: var(--spacer);
} }
.section {
margin-top: calc(var(--spacer) * 1.5);
}
.section:last-child {
margin-bottom: 0;
}
.sectionTitle {
font-size: var(--font-size-h3);
margin-bottom: calc(var(--spacer) / 2);
}

View File

@ -0,0 +1,45 @@
import React, { ReactElement, ReactNode } from 'react'
import styles from './index.module.css'
import PoolTransactions from './PoolTransactions'
import PublishedList from './PublishedList'
const sections = [
{
title: 'Published',
component: <PublishedList />
},
{
title: 'Pool Transactions',
component: <PoolTransactions />
},
{
title: 'Compute Jobs',
component: 'Coming Soon...'
}
]
const Section = ({
title,
component
}: {
title: string
component: ReactNode
}) => {
return (
<div className={styles.section}>
<h2 className={styles.sectionTitle}>{title}</h2>
{component}
</div>
)
}
export default function HistoryPage(): ReactElement {
return (
<article className={styles.content}>
{sections.map((section) => {
const { title, component } = section
return <Section key={title} title={title} component={component} />
})}
</article>
)
}

View File

@ -1,4 +1,4 @@
import { MetadataMarket, MetadataPublishForm } from '../../../@types/Metadata' import { MetadataMarket, MetadataPublishForm } from '../../../@types/MetaData'
import { toStringNoMS } from '../../../utils' import { toStringNoMS } from '../../../utils'
import AssetModel from '../../../models/Asset' import AssetModel from '../../../models/Asset'

View File

@ -2,7 +2,7 @@ import React, { useState, useEffect, ReactElement } from 'react'
import { Router } from '@reach/router' import { Router } from '@reach/router'
import AssetContent from '../../components/organisms/AssetContent' import AssetContent from '../../components/organisms/AssetContent'
import Layout from '../../components/Layout' import Layout from '../../components/Layout'
import { MetadataMarket } from '../../@types/Metadata' import { MetadataMarket } from '../../@types/MetaData'
import { MetadataStore, Logger, DDO } from '@oceanprotocol/lib' import { MetadataStore, Logger, DDO } from '@oceanprotocol/lib'
import Alert from '../../components/atoms/Alert' import Alert from '../../components/atoms/Alert'
import Loader from '../../components/atoms/Loader' import Loader from '../../components/atoms/Loader'

View File

@ -1,4 +1,4 @@
import { MetadataMarket } from '../@types/Metadata' import { MetadataMarket } from '../@types/MetaData'
const AssetModel: MetadataMarket = { const AssetModel: MetadataMarket = {
// OEP-8 Attributes // OEP-8 Attributes

View File

@ -1,4 +1,4 @@
import { MetadataPublishForm } from '../@types/Metadata' import { MetadataPublishForm } from '../@types/MetaData'
import { File as FileMetadata } from '@oceanprotocol/lib' import { File as FileMetadata } from '@oceanprotocol/lib'
import * as Yup from 'yup' import * as Yup from 'yup'

View File

@ -1,5 +1,5 @@
import AssetModel from '../../src/models/Asset' import AssetModel from '../../src/models/Asset'
import { MetadataMarket } from '../../src/@types/Metadata' import { MetadataMarket } from '../../src/@types/MetaData'
describe('AssetModel', () => { describe('AssetModel', () => {
it('values can be reassigned', () => { it('values can be reassigned', () => {

View File

@ -1,265 +1,86 @@
import { DDO } from '@oceanprotocol/lib' import { DDO } from '@oceanprotocol/lib'
import {
MetadataMarket,
ServiceMetadataMarket
} from '../../../src/@types/Metadata'
const ddo: Partial<DDO> = { const ddo: Partial<DDO> = {
'@context': 'https://w3id.org/did/v1', '@context': 'https://w3id.org/did/v1',
id: 'did:op:e6fda48e8d814d5d9655645aac3c046cc87528dbc1a9449799e579d7b83d1360', id: 'did:op:7b4e90b05ec243dbaaca2a503fdde119706577f9645b45b9ab65cf2c3970f757',
publicKey: [ publicKey: [
{ {
id: id:
'did:op:e6fda48e8d814d5d9655645aac3c046cc87528dbc1a9449799e579d7b83d1360', 'did:op:7b4e90b05ec243dbaaca2a503fdde119706577f9645b45b9ab65cf2c3970f757',
type: 'EthereumECDSAKey', type: 'EthereumECDSAKey',
owner: '0x610D9314EDF2ced7681BA1633C33fdb8cF365a12' owner: '0x4D156A2ef69ffdDC55838176C6712C90f60a2285'
} }
], ],
authentication: [ authentication: [
{ {
type: 'RsaSignatureAuthentication2018', type: 'RsaSignatureAuthentication2018',
publicKey: publicKey:
'did:op:e6fda48e8d814d5d9655645aac3c046cc87528dbc1a9449799e579d7b83d1360' 'did:op:7b4e90b05ec243dbaaca2a503fdde119706577f9645b45b9ab65cf2c3970f757'
} }
], ],
service: [ service: [
{ {
type: 'metadata', type: 'metadata',
serviceEndpoint: attributes: {
'https://aquarius.pacific.dev-ocean.com/api/v1/aquarius/assets/ddo/did:op:e6fda48e8d814d5d9655645aac3c046cc87528dbc1a9449799e579d7b83d1360',
attributes: ({
main: { main: {
type: 'dataset', type: 'dataset',
name: 'What a Waste Global Database', name: 'Endangered coral reefs',
dateCreated: '2018-09-20T08:38:58', dateCreated: '2020-09-21T09:58:35Z',
datePublished: '2019-12-11T05:19:42', author: 'me',
author: 'World Development Indicators, The World Bank', license:
license: 'CC-BY 4.0', 'CC BY-NC-SA: Attribution-NonCommercial-ShareAlike 4.0 International',
price: '100000000000000000000',
files: [ files: [
{ {
index: 0, contentLength: '1256',
contentType: 'csv', contentType: 'text/html',
contentLength: '114000', index: 0
url: ''
},
{
index: 1,
contentType: 'excel',
contentLength: '219000',
url: ''
},
{
index: 2,
contentType: 'csv',
contentLength: '1300000',
url: ''
},
{
index: 3,
contentType: 'csv',
contentLength: '36300',
url: ''
} }
] ],
datePublished: '2020-09-21T09:59:07Z'
}, },
additionalInformation: { additionalInformation: {
description: description: 'test',
'What a Waste is a global project to aggregate data on solid waste management from around the world. This database features the statistics collected through the effort, covering nearly all countries and over 330 cities. The metrics included cover all steps from the waste management value chain, including waste generation, composition, collection, and disposal, as well as information on user fees and financing, the informal sector, administrative structures, public communication, and legal information. The information presented is the best available based on a study of current literature and limited conversations with waste agencies and authorities. While there may be variations in the definitions and quality of reporting for individual data points, general trends should reflect the global reality. All sources and any estimations are noted.', copyrightHolder: '',
copyrightHolder: 'World Bank Group', tags: ['coral'],
tags: ['Sustainability', ' Climate', ' Energy', ' ai-for-good'],
links: [ links: [
{ {
name: 'Hello', contentLength: '1256',
url: 'https://demo.com' contentType: 'text/html',
url: 'https://www.example.com'
} }
], ],
termsAndConditions: true, termsAndConditions: true,
access: 'Download' priceType: 'fixed'
},
curation: {
numVotes: 100,
rating: 5
} }
} as unknown) as MetadataMarket,
index: 0
} as ServiceMetadataMarket,
{
type: 'authorization',
serviceEndpoint: 'https://secret-store.pacific.oceanprotocol.com',
attributes: {
main: {}
}, },
index: 2 index: 0
}, },
{ {
type: 'access', type: 'access',
index: 1,
serviceEndpoint: serviceEndpoint:
'https://brizo.pacific.dev-ocean.com/api/v1/brizo/services/consume', 'https://provider.rinkeby.v3.dev-ocean.com/api/v1/services/consume',
attributes: { attributes: {
serviceAgreementTemplate: {
contractName: 'EscrowAccessSecretStoreTemplate',
events: [
{
name: 'AgreementCreated',
actorType: 'consumer',
handler: {
moduleName: 'escrowAccessSecretStoreTemplate',
functionName: 'fulfillLockRewardCondition',
version: '0.1'
}
}
],
fulfillmentOrder: [
'lockReward.fulfill',
'accessSecretStore.fulfill',
'escrowReward.fulfill'
],
conditionDependency: {
lockReward: [],
accessSecretStore: [],
escrowReward: ['lockReward', 'accessSecretStore']
},
conditions: [
{
name: 'lockReward',
timelock: 0,
timeout: 0,
contractName: 'LockRewardCondition',
functionName: 'fulfill',
events: [
{
name: 'Fulfilled',
actorType: 'publisher',
handler: {
moduleName: 'lockRewardCondition',
functionName: 'fulfillAccessSecretStoreCondition',
version: '0.1'
}
}
],
parameters: [
{
name: '_rewardAddress',
type: 'address',
value: '0x656Aa3D9b37A6eA770701ae2c612f760d9254A66'
},
{
name: '_amount',
type: 'uint256',
value: '0'
}
]
},
{
name: 'accessSecretStore',
timelock: 0,
timeout: 0,
contractName: 'AccessSecretStoreCondition',
functionName: 'fulfill',
events: [
{
name: 'Fulfilled',
actorType: 'publisher',
handler: {
moduleName: 'accessSecretStore',
functionName: 'fulfillEscrowRewardCondition',
version: '0.1'
}
},
{
name: 'TimedOut',
actorType: 'consumer',
handler: {
moduleName: 'accessSecretStore',
functionName: 'fulfillEscrowRewardCondition',
version: '0.1'
}
}
],
parameters: [
{
name: '_documentId',
type: 'bytes32',
value:
'e6fda48e8d814d5d9655645aac3c046cc87528dbc1a9449799e579d7b83d1360'
},
{
name: '_grantee',
type: 'address',
value: ''
}
]
},
{
name: 'escrowReward',
timelock: 0,
timeout: 0,
contractName: 'EscrowReward',
functionName: 'fulfill',
events: [
{
name: 'Fulfilled',
actorType: 'publisher',
handler: {
moduleName: 'escrowRewardCondition',
functionName: 'verifyRewardTokens',
version: '0.1'
}
}
],
parameters: [
{
name: '_amount',
type: 'uint256',
value: '0'
},
{
name: '_receiver',
type: 'address',
value: ''
},
{
name: '_sender',
type: 'address',
value: ''
},
{
name: '_lockCondition',
type: 'bytes32',
value: ''
},
{
name: '_releaseCondition',
type: 'bytes32',
value: ''
}
]
}
]
},
additionalInformation: {
description: ''
},
main: { main: {
name: 'dataAssetAccessServiceAgreement', creator: '0x4D156A2ef69ffdDC55838176C6712C90f60a2285',
creator: '', datePublished: '2020-09-21T09:58:35Z',
datePublished: '2019-12-11T05:19:42Z', cost: '1000000000000000000',
price: '', timeout: 0,
timeout: 36000 name: 'dataAssetAccess'
} }
}, }
index: 3
} }
], ],
created: '2019-06-26T14:53:09', dataToken: '0x932c3937cBc983790e67A258Cb6F8959F2466407',
created: '2020-09-21T09:59:01Z',
proof: { proof: {
created: '2020-09-21T09:59:06Z',
creator: '0x4D156A2ef69ffdDC55838176C6712C90f60a2285',
type: 'DDOIntegritySignature', type: 'DDOIntegritySignature',
created: '2019-06-26T14:53:14Z',
creator: '0x610D9314EDF2ced7681BA1633C33fdb8cF365a12',
signatureValue: signatureValue:
'0x989cda083ff1711f885bf0fa95a149654edb07da7698b8f4bb3482788b1960f562aa265259767de8ed03a1d1bdaa1885cf42c5a41ec33145e84975ae7444f0d91b' '0xc2157630d4f15d1575f1320ee1ea8007c750e8b06f5866941cc8372596cde39424dff2a75c2b9ac16683add2c2d1972f77953f207239191c7a48af64c4deb8c21c'
} },
updated: '2020-09-21T09:59:01Z'
} }
export default ddo export default ddo

View File

@ -1,20 +0,0 @@
import { ComputeJob } from '@oceanprotocol/lib'
// ComputeJob need to be updated in squid
const job: Partial<ComputeJob> = {
agreementId:
'ccc60b8d33ae4986b224551b69f521761171159994474debbb5353f45286e206',
algorithmLogUrl:
'https://compute-publish.s3.amazonaws.com/605fb38b076844b7a2ee912b229a3f73/data/logs/algorithm.log',
dateCreated: '1585828421.03217',
dateFinished: '1585828541.73514',
jobId: '605fb38b076844b7a2ee912b229a3f7333',
owner: '0x4D156A2ef69ffdDC55838176C6712C90f60a2285',
resultsUrls: [
'https://compute-publish.s3.amazonaws.com/605fb38b076844b7a2ee912b229a3f73/data/outputs/output.log'
],
status: 70,
statusText: 'Job finished'
}
export default job

View File

@ -1,4 +1,4 @@
import { MetadataPublishForm } from '../../../src/@types/Metadata' import { MetadataPublishForm } from '../../../src/@types/MetaData'
const testFormData: MetadataPublishForm = { const testFormData: MetadataPublishForm = {
author: '', author: '',

View File

@ -1,5 +1,4 @@
import ddo from '../../__fixtures__/ddo' import ddo from '../../__fixtures__/ddo'
import job from '../../__fixtures__/job'
const metadataStore = { const metadataStore = {
queryMetadata: () => { queryMetadata: () => {
@ -19,11 +18,11 @@ const libMock = {
list: () => ['xxx', 'xxx'] list: () => ['xxx', 'xxx']
}, },
metadataStore, metadataStore,
compute: { // compute: {
status: (account: string) => { // status: (account: string) => {
return [job] // return [job]
} // }
}, // },
assets: { assets: {
query: () => { query: () => {
return { return {

View File

@ -13,9 +13,9 @@ const reactMock = {
return { return {
ocean: libMock.ocean, ocean: libMock.ocean,
config: {}, config: {},
web3: null, web3: null as any,
web3Modal: null, web3Modal: null as any,
web3Provider: null, web3Provider: null as any,
accountId: '0x0000000011111111aaaaaaaabbbbbbbb22222222', accountId: '0x0000000011111111aaaaaaaabbbbbbbb22222222',
balance: '0.12' balance: '0.12'
} }

View File

@ -4,7 +4,7 @@ import { transformPublishFormToMetadata } from '../../../src/components/pages/Pu
import { import {
MetadataMarket, MetadataMarket,
MetadataPublishForm MetadataPublishForm
} from '../../../src/@types/Metadata' } from '../../../src/@types/MetaData'
import PublishForm from '../../../src/components/pages/Publish/PublishForm' import PublishForm from '../../../src/components/pages/Publish/PublishForm'
import publishFormData from '../__fixtures__/testFormData' import publishFormData from '../__fixtures__/testFormData'
import content from '../../../content/pages/publish.json' import content from '../../../content/pages/publish.json'

View File

@ -13,7 +13,8 @@
"sourceMap": true, "sourceMap": true,
"noImplicitAny": true, "noImplicitAny": true,
"skipLibCheck": true, "skipLibCheck": true,
"allowJs": true "allowJs": true,
"baseUrl": "./src"
}, },
"exclude": ["node_modules", "public", ".cache", "*.js"], "exclude": ["node_modules", "public", ".cache", "*.js"],
"include": ["./src/**/*", "./tests/**/*", "./app.config.js"] "include": ["./src/**/*", "./tests/**/*", "./app.config.js"]