1
0
mirror of https://github.com/oceanprotocol/market.git synced 2024-12-02 05:57:29 +01:00

purgatory updates (#249)

* purgatory updates

Signed-off-by: mihaisc <mihai.scarlat@smartcontrol.ro>

* format

* update react hooks

* alert style, copy changes

* remove inverse style

* disable remove for purgatory owner

Signed-off-by: mihaisc <mihai.scarlat@smartcontrol.ro>

* remove buy button for purgatory assets

* hide remove liquidity for owner

* query change

* query rollback

* query change

* query change

* query change

* change frontpage queries

* typings

* query refactor, make `all data sets` link work again

* footer fix

* test endpoint for stats

* fix pagination

Signed-off-by: mihaisc <mihai.scarlat@smartcontrol.ro>

* partner query tweaks

* switch back market-stats endpoint

Co-authored-by: Matthias Kretschmann <m@kretschmann.io>
This commit is contained in:
mihaisc 2020-11-14 16:02:54 +02:00 committed by GitHub
parent 95d62024bd
commit f8a0ff41c3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 196 additions and 71 deletions

26
package-lock.json generated
View File

@ -3550,9 +3550,9 @@
"integrity": "sha512-p0oOHXr60hXZuLNsQ/PsOQtCfia79thm7MjPxTrnnBvD+csJoHzARYMB0IFj/KTw6U5vLXODgjJAn8x6QksLwg=="
},
"@oceanprotocol/lib": {
"version": "0.9.10",
"resolved": "https://registry.npmjs.org/@oceanprotocol/lib/-/lib-0.9.10.tgz",
"integrity": "sha512-IUL3K0RYisW5iodncf7pJJMnR9k/89TKfenI5TsMALTX71Vuf6NyX+lW0+rui0b0ZiKn5v0xHIlgJy8JEvo8+g==",
"version": "0.9.12",
"resolved": "https://registry.npmjs.org/@oceanprotocol/lib/-/lib-0.9.12.tgz",
"integrity": "sha512-R52kWSwwpKNzNHfnNbF6seFPvXEtExK3bWIi4V4eIkgmAf272sa6PVza4mJrtEpTAS1WcJv5ihF7cczIDecxbg==",
"requires": {
"@ethereum-navigator/navigator": "^0.5.0",
"@oceanprotocol/contracts": "^0.5.7",
@ -3567,16 +3567,16 @@
}
},
"@oceanprotocol/list-datapartners": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@oceanprotocol/list-datapartners/-/list-datapartners-1.0.2.tgz",
"integrity": "sha512-7WCQyiaNuUMhXh0x3cS/l4Fv34mjZTrXueOzVTfirE+2DD/8Y/BrtBbFV6tYZ0ALjUEulExEAW6ELqn4qSDQHg=="
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@oceanprotocol/list-datapartners/-/list-datapartners-1.0.3.tgz",
"integrity": "sha512-MMyy81FvnRGwl2cQ4+cucq/YWjUTGzStHyAUVM6P2pFA8zMc3jouuWN2WSAjmvhxeKZU7jvJRwZCoi+miEYKjw=="
},
"@oceanprotocol/react": {
"version": "0.3.16",
"resolved": "https://registry.npmjs.org/@oceanprotocol/react/-/react-0.3.16.tgz",
"integrity": "sha512-HzOlsI/LKxl01KkjNFEem7gwHWPquWcJ4o7cy8iBOIypTMOHt4bTtepobY5jP0RT04inHFuQDQYsYTDRdg8A1w==",
"version": "0.3.19",
"resolved": "https://registry.npmjs.org/@oceanprotocol/react/-/react-0.3.19.tgz",
"integrity": "sha512-9esHRLJlfCtGRA8PRuohiYoCitos2DgZjGxY+og5k4udwiqSHKzHV1fJexu9rGknKQls7o+QIt4I/79jpnqETw==",
"requires": {
"@oceanprotocol/lib": "^0.9.9",
"@oceanprotocol/lib": "^0.9.12",
"axios": "^0.21.0",
"decimal.js": "^10.2.1",
"web3": "^1.3.0",
@ -31796,9 +31796,9 @@
}
},
"styled-components": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/styled-components/-/styled-components-5.2.0.tgz",
"integrity": "sha512-9qE8Vgp8C5cpGAIdFaQVAl89Zgx1TDM4Yf4tlHbO9cPijtpSXTMLHy9lmP0lb+yImhgPFb1AmZ1qMUubmg3HLg==",
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/styled-components/-/styled-components-5.2.1.tgz",
"integrity": "sha512-sBdgLWrCFTKtmZm/9x7jkIabjFNVzCUeKfoQsM6R3saImkUnjx0QYdLwJHBjY9ifEcmjDamJDVfknWm1yxZPxQ==",
"requires": {
"@babel/helper-module-imports": "^7.0.0",
"@babel/traverse": "^7.4.5",

View File

@ -24,9 +24,9 @@
"@coingecko/cryptoformat": "^0.4.2",
"@loadable/component": "^5.14.1",
"@oceanprotocol/art": "^3.0.0",
"@oceanprotocol/lib": "^0.9.10",
"@oceanprotocol/lib": "^0.9.12",
"@oceanprotocol/list-datapartners": "^1.0.3",
"@oceanprotocol/react": "^0.3.16",
"@oceanprotocol/react": "^0.3.19",
"@oceanprotocol/typographies": "^0.1.0",
"@sindresorhus/slugify": "^1.0.0",
"@tippyjs/react": "^4.2.0",

View File

@ -25,7 +25,3 @@
/* sticky footer technique */
flex: 1;
}
.banner {
margin-bottom: -2rem !important;
}

View File

@ -1,4 +1,4 @@
import React, { ReactNode, ReactElement } from 'react'
import React, { ReactNode, ReactElement, useEffect } from 'react'
import Header from './organisms/Header'
import Footer from './organisms/Footer'
import PageHeader from './molecules/PageHeader'
@ -7,6 +7,8 @@ import Seo from './atoms/Seo'
import Container from './atoms/Container'
import Alert from './atoms/Alert'
import { useSiteMetadata } from '../hooks/useSiteMetadata'
import { useAsset, useOcean } from '@oceanprotocol/react'
import { Logger } from '@oceanprotocol/lib'
export interface LayoutProps {
children: ReactNode
@ -26,6 +28,15 @@ export default function Layout({
headerCenter
}: LayoutProps): ReactElement {
const { warning } = useSiteMetadata()
const { isInPurgatory, purgatoryData } = useAsset()
const {
isInPurgatory: isAccountInPurgatory,
purgatoryData: accountPurgatory
} = useOcean()
useEffect(() => {
Logger.log('isInPurgatory', isInPurgatory, purgatoryData)
}, [isInPurgatory, purgatoryData])
return (
<div className={styles.app}>
@ -37,6 +48,24 @@ export default function Layout({
<Alert text={warning} state="info" className={styles.banner} />
)}
{isAccountInPurgatory && accountPurgatory && (
<Alert
title="Account In Purgatory"
badge={`Reason: ${accountPurgatory.reason}`}
text="No further actions are permitted by this account. For more details go to [list-purgatory](https://github.com/oceanprotocol/list-purgatory)."
state="error"
/>
)}
{isInPurgatory && purgatoryData && (
<Alert
title="Data Set In Purgatory"
badge={`Reason: ${purgatoryData.reason}`}
text="Except for removing liquidity, no further actions are permitted on this data set and it will not be returned in any search. For more details go to [list-purgatory](https://github.com/oceanprotocol/list-purgatory)."
state="error"
/>
)}
<main className={styles.main}>
<Container>
{title && !noPageHeader && (

View File

@ -26,10 +26,21 @@
color: inherit;
}
.badge {
vertical-align: middle;
margin-left: calc(var(--spacer) / 8);
margin-top: -0.3rem;
}
.text {
font-size: var(--font-size-small);
}
.text a {
color: inherit;
text-decoration: underline;
}
.text p:last-child {
margin-bottom: 0;
}
@ -58,7 +69,7 @@
/* States */
.error {
border-color: var(--rbrand-alert-ed);
border-color: var(--brand-alert-red);
color: var(--brand-alert-red);
}

View File

@ -3,11 +3,13 @@ import classNames from 'classnames/bind'
import styles from './Alert.module.css'
import Button from './Button'
import Markdown from './Markdown'
import Badge from './Badge'
const cx = classNames.bind(styles)
export default function Alert({
title,
badge,
text,
state,
action,
@ -15,6 +17,7 @@ export default function Alert({
className
}: {
title?: string
badge?: string
text: string
state: 'error' | 'warning' | 'info' | 'success'
action?: {
@ -33,7 +36,11 @@ export default function Alert({
return (
<div className={styleClasses}>
{title && <h3 className={styles.title}>{title}</h3>}
{title && (
<h3 className={styles.title}>
{title} {badge && <Badge className={styles.badge} label={badge} />}
</h3>
)}
<Markdown className={styles.text} text={text} />
{action && (
<Button

View File

@ -4,7 +4,7 @@
font-weight: var(--font-weight-bold);
line-height: 1;
text-transform: uppercase;
padding: 0.1rem 0.2rem;
padding: 0.2rem 0.2rem 0.1rem 0.2rem;
border-radius: var(--border-radius);
color: var(--brand-white);
background: var(--brand-purple);

View File

@ -1,5 +1,6 @@
import React, { ReactElement } from 'react'
import React, { ReactElement, useEffect, useState } from 'react'
import { format, formatDistance } from 'date-fns'
import { setDate } from 'date-fns/esm'
export default function Time({
date,
@ -12,10 +13,16 @@ export default function Time({
isUnix?: boolean
className?: string
}): ReactElement {
const [dateIso, setDateIso] = useState<string>()
const [dateNew, setDateNew] = useState<Date>()
useEffect(() => {
if (!date) return
const dateNew = isUnix ? new Date(Number(date) * 1000) : new Date(date)
const dateIso = dateNew.toISOString()
setDateIso(dateNew.toISOString())
setDateNew(dateNew)
}, [date])
return !date ? (
return !dateIso || !dateNew ? (
<></>
) : (
<time

View File

@ -26,7 +26,7 @@ export default function SearchBar({
function startSearch(e: FormEvent<HTMLButtonElement>) {
e.preventDefault()
if (value === '') return
navigate(`/search/?text=${value}`)
navigate(`/search?text=${value}`)
}
return (

View File

@ -7,7 +7,12 @@ import Price from '../../atoms/Price'
import Web3Feedback from '../../molecules/Wallet/Feedback'
import styles from './Consume.module.css'
import Loader from '../../atoms/Loader'
import { useOcean, useConsume, usePricing } from '@oceanprotocol/react'
import {
useOcean,
useConsume,
usePricing,
useAsset
} from '@oceanprotocol/react'
import { useSiteMetadata } from '../../../hooks/useSiteMetadata'
import checkPreviousOrder from '../../../utils/checkPreviousOrder'
@ -26,7 +31,7 @@ export default function Consume({
const { marketFeeAddress } = useSiteMetadata()
const [hasPreviousOrder, setHasPreviousOrder] = useState(false)
const [previousOrderId, setPreviousOrderId] = useState<string>()
const { isInPurgatory } = useAsset()
const {
dtSymbol,
buyDT,
@ -47,7 +52,13 @@ export default function Consume({
pricingIsLoading) &&
!hasPreviousOrder
)
}, [hasPreviousOrder, isBalanceSufficient, consumeStepText, pricingIsLoading])
}, [
ocean,
hasPreviousOrder,
isBalanceSufficient,
consumeStepText,
pricingIsLoading
])
useEffect(() => {
if (!ocean || !accountId) return
@ -104,7 +115,7 @@ export default function Consume({
without paying again.
</div>
)}
<PurchaseButton />
{!isInPurgatory && <PurchaseButton />}
</div>
</div>

View File

@ -1,5 +1,10 @@
import React, { ReactElement, useEffect, useState } from 'react'
import { useOcean, useMetadata, usePricing } from '@oceanprotocol/react'
import {
useOcean,
useMetadata,
usePricing,
useAsset
} from '@oceanprotocol/react'
import { DDO, Logger } from '@oceanprotocol/lib'
import styles from './index.module.css'
import stylesActions from './Actions.module.css'
@ -47,6 +52,7 @@ export default function Pool({ ddo }: { ddo: DDO }): ReactElement {
const { ocean, accountId, networkId } = useOcean()
const { price, refreshPrice, owner } = useMetadata(ddo)
const { dtSymbol } = usePricing(ddo)
const { isInPurgatory } = useAsset()
const [poolTokens, setPoolTokens] = useState<string>()
const [totalPoolTokens, setTotalPoolTokens] = useState<string>()
@ -57,6 +63,7 @@ export default function Pool({ ddo }: { ddo: DDO }): ReactElement {
const [showAdd, setShowAdd] = useState(false)
const [showRemove, setShowRemove] = useState(false)
const [isRemoveDisabled, setIsRemoveDisabled] = useState(false)
const [hasAddedLiquidity, setHasAddedLiquidity] = useState(false)
const [poolShare, setPoolShare] = useState<string>()
@ -73,6 +80,10 @@ export default function Pool({ ddo }: { ddo: DDO }): ReactElement {
// the purpose of the value is just to trigger the effect
const [refreshPool, setRefreshPool] = useState(false)
useEffect(() => {
setIsRemoveDisabled(isInPurgatory && owner === accountId)
}, [isInPurgatory, owner, accountId])
useEffect(() => {
const poolShare =
price?.ocean &&
@ -291,15 +302,18 @@ export default function Pool({ ddo }: { ddo: DDO }): ReactElement {
)}
<div className={stylesActions.actions}>
{!isInPurgatory && (
<Button
style="primary"
size="small"
onClick={() => setShowAdd(true)}
disabled={isInPurgatory}
>
Add Liquidity
</Button>
)}
{hasAddedLiquidity && (
{hasAddedLiquidity && !isRemoveDisabled && (
<Button size="small" onClick={() => setShowRemove(true)}>
Remove
</Button>

View File

@ -13,6 +13,7 @@ import { useMetadata, useOcean, usePricing } from '@oceanprotocol/react'
import EtherscanLink from '../../atoms/EtherscanLink'
import Bookmark from './Bookmark'
import Byline from './Byline'
import Alert from '../../atoms/Alert'
export interface AssetContentProps {
metadata: MetadataMarket
@ -28,7 +29,6 @@ export default function AssetContent({
const { accountId, networkId } = useOcean()
const { owner } = useMetadata(ddo)
const { dtSymbol, dtName } = usePricing(ddo)
const isOwner = accountId === owner
const hasNoPrice = ddo.price.datatoken === 0 && ddo.price.value === 0
const showPricing = isOwner && hasNoPrice
@ -37,7 +37,6 @@ export default function AssetContent({
<article className={styles.grid}>
<div>
{showPricing && <Pricing ddo={ddo} />}
<div className={styles.content}>
<p className={styles.author} title="Author">
{metadata?.main.author}

View File

@ -5,7 +5,7 @@
}
.content {
padding: calc(var(--spacer) / 2);
padding: var(--spacer) calc(var(--spacer) / 2);
margin-left: auto;
margin-right: auto;
max-width: var(--layout-max-width);
@ -23,3 +23,7 @@
.content a:focus {
color: var(--color-primary);
}
.copyright div {
display: inline-block;
}

View File

@ -14,11 +14,15 @@ export default function Footer(): ReactElement {
<footer className={styles.footer}>
<div className={styles.content}>
<BuildId />
<MarketStats />© {year} <Markdown text={copyright} /> {' '}
<MarketStats />
<div className={styles.copyright}>
© {year} <Markdown text={copyright} /> {' '}
<Link to="/terms">Terms</Link>
{' — '}
<a href="https://oceanprotocol.com/privacy">Privacy</a>
</div>
</div>
</footer>
)
}

View File

@ -16,28 +16,48 @@ import listPartners from '@oceanprotocol/list-datapartners'
import Tooltip from '../atoms/Tooltip'
import AssetQueryCarousel from '../organisms/AssetQueryCarousel'
const partnerAccounts = listPartners.map((partner) =>
partner.accounts.join(',')
)
const partnerAccounts = listPartners
.map((partner) => partner.accounts.join(','))
.filter((account) => account !== '')
const queryHighest = {
page: 1,
offset: 9,
query: { 'price.type': ['pool'] },
sort: { 'price.ocean': -1 }
}
const searchAccounts = JSON.stringify(partnerAccounts)
.replace(/"/g, '')
.replace(/,/g, ' OR ')
.replace(/(\[|\])/g, '')
const queryPartners = {
page: 1,
offset: 100,
query: { 'publicKey.owner': partnerAccounts },
query: {
nativeSearch: 1,
query_string: {
query: `(publicKey.owner:${searchAccounts}) -isInPurgatory:true`
}
},
sort: { created: -1 }
}
const queryHighest = {
page: 1,
offset: 9,
query: {
nativeSearch: 1,
query_string: {
query: `(price.type:pool) -isInPurgatory:true`
}
},
sort: { 'price.ocean': -1 }
}
const queryLatest = {
page: 1,
offset: 9,
query: {},
query: {
nativeSearch: 1,
query_string: {
query: `-isInPurgatory:true`
}
},
sort: { created: -1 }
}
@ -92,21 +112,22 @@ export default function HomePage(): ReactElement {
const [loading, setLoading] = useState(true)
useEffect(() => {
// TODO: remove any once ocean.js has nativeSearch typings
async function init() {
const queryResultHighest = await getAssets(
queryHighest,
queryHighest as any,
config.metadataCacheUri
)
setQueryResultHighest(queryResultHighest)
const queryResultPartners = await getAssets(
queryPartners,
queryPartners as any,
config.metadataCacheUri
)
setQueryResultPartners(queryResultPartners)
const queryResultLatest = await getAssets(
queryLatest,
queryLatest as any,
config.metadataCacheUri
)
setQueryResultLatest(queryResultLatest)

View File

@ -1,6 +1,6 @@
import React, { ReactElement, useState } from 'react'
import { Formik } from 'formik'
import { usePublish } from '@oceanprotocol/react'
import { usePublish, useOcean } from '@oceanprotocol/react'
import styles from './index.module.css'
import FormPublish from './FormPublish'
import Web3Feedback from '../../molecules/Wallet/Feedback'
@ -25,7 +25,7 @@ export default function PublishPage({
}): ReactElement {
const { debug } = useUserPreferences()
const { publish, publishError, isLoading, publishStepText } = usePublish()
const { isInPurgatory, purgatoryData } = useOcean()
const [success, setSuccess] = useState<string>()
const [error, setError] = useState<string>()
const [ddo, setDdo] = useState<DDO>()
@ -72,7 +72,7 @@ export default function PublishPage({
}
}
return (
return isInPurgatory && purgatoryData ? null : (
<Formik
initialValues={initialValues}
initialStatus="empty"

View File

@ -12,14 +12,27 @@ export function getSearchQuery(
page?: string,
offset?: string
): SearchQuery {
const searchTerm = owner
? `(publicKey.owner:${owner})`
: tags
? // eslint-disable-next-line no-useless-escape
`(service.attributes.additionalInformation.tags:\"${tags}\")`
: categories
? // eslint-disable-next-line no-useless-escape
`(service.attributes.additionalInformation.categories:\"${categories}\")`
: text || ''
return {
page: Number(page) || 1,
offset: Number(offset) || 21,
query: {
text,
...(owner && { 'publicKey.owner': [owner] }),
...(tags && { tags: [tags] }),
...(categories && { categories: [categories] })
nativeSearch: 1,
query_string: {
query: `${searchTerm} -isInPurgatory:true`
}
// ...(owner && { 'publicKey.owner': [owner] }),
// ...(tags && { tags: [tags] }),
// ...(categories && { categories: [categories] })
},
sort: {
created: -1
@ -29,7 +42,11 @@ export function getSearchQuery(
// which is the only way the query actually returns desired results.
// But it doesn't follow 'SearchQuery' interface so we have to assign
// it here.
} as SearchQuery
// } as SearchQuery
// And the next hack,
// nativeSearch is not implmeneted on ocean.js typings
} as any
}
export async function getResults(

View File

@ -1,9 +1,14 @@
import React, { ReactElement } from 'react'
import { PageProps } from 'gatsby'
import PageTemplateAssetDetails from '../../components/templates/AssetDetails'
import { AssetProvider } from '@oceanprotocol/react'
export default function PageGatsbyAssetDetails(props: PageProps): ReactElement {
const did = props.location.pathname.split('/')[2]
return <PageTemplateAssetDetails did={did} uri={props.location.pathname} />
return (
<AssetProvider asset={did}>
<PageTemplateAssetDetails did={did} uri={props.location.pathname} />
</AssetProvider>
)
}