1
0
mirror of https://github.com/oceanprotocol/market.git synced 2024-11-14 17:24:51 +01:00

Merge branch 'feature/compute' into publish-algo

This commit is contained in:
Bogdan Fazakas 2021-03-03 16:13:03 +02:00 committed by GitHub
commit 32ff7af3ce
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 386 additions and 162 deletions

View File

@ -0,0 +1,16 @@
.icon {
fill: var(--brand-grey-light);
width: 1.1em;
height: 1.1em;
vertical-align: baseline;
margin-bottom: -0.2em;
display: inline-block;
}
.typeLabel {
display: inline-block;
text-transform: uppercase;
border-right: 1px solid var(--border-color);
padding-right: calc(var(--spacer) / 3.5);
margin-right: calc(var(--spacer) / 4);
}

View File

@ -0,0 +1,33 @@
import React, { ReactElement } from 'react'
import styles from './AssetType.module.css'
import classNames from 'classnames/bind'
import { ReactComponent as Compute } from '../../images/compute.svg'
import { ReactComponent as Download } from '../../images/download.svg'
const cx = classNames.bind(styles)
export default function AssetType({
type,
accessType,
className
}: {
type: string
accessType: string
className?: string
}): ReactElement {
const styleClasses = cx({
[className]: className
})
return (
<div className={styleClasses}>
<div className={styles.typeLabel}>
{type === 'dataset' ? 'data set' : 'algorithm'}
</div>
{accessType === 'access' ? (
<Download role="img" aria-label="Download" className={styles.icon} />
) : (
<Compute role="img" aria-label="Compute" className={styles.icon} />
)}
</div>
)
}

View File

@ -6,7 +6,7 @@
border: 1px solid var(--border-color); border: 1px solid var(--border-color);
box-shadow: none; box-shadow: none;
width: 100%; width: 100%;
background: var(--background-body); background: var(--background-content);
padding: calc(var(--spacer) / 3); padding: calc(var(--spacer) / 3);
margin: 0; margin: 0;
border-radius: var(--border-radius); border-radius: var(--border-radius);

View File

@ -28,10 +28,15 @@ export default function Price({
conversion={conversion} conversion={conversion}
type={price.type} type={price.type}
/> />
) : !price || price?.value === 0 ? ( ) : !price || !price.address || price.address === '' ? (
<div className={styles.empty}> <div className={styles.empty}>
No price found{' '} No price set{' '}
<Tooltip content="We could not find a pool for this data set, which can have multiple reasons. Is your wallet connected to the correct network?" /> <Tooltip content="No pricing mechanism has been set on this asset yet." />
</div>
) : price.isConsumable !== 'true' ? (
<div className={styles.empty}>
Low liquidity{' '}
<Tooltip content="This pool does not have enough liquidity for using this data set." />
</div> </div>
) : ( ) : (
<Loader message="Retrieving price..." /> <Loader message="Retrieving price..." />

View File

@ -2,7 +2,7 @@ import { DDO } from '@oceanprotocol/lib'
import { useOcean } from '@oceanprotocol/react' import { useOcean } from '@oceanprotocol/react'
import { Link } from 'gatsby' import { Link } from 'gatsby'
import React, { ReactElement, useEffect, useState } from 'react' import React, { ReactElement, useEffect, useState } from 'react'
import { retrieveDDO } from '../../utils/aquarius' import { retrieveDDO, getAssetsNames } from '../../utils/aquarius'
import styles from './AssetListTitle.module.css' import styles from './AssetListTitle.module.css'
import axios from 'axios' import axios from 'axios'
@ -28,15 +28,16 @@ export default function AssetListTitle({
const source = axios.CancelToken.source() const source = axios.CancelToken.source()
async function getDDO() { async function getAssetName() {
const ddo = await retrieveDDO(did, config.metadataCacheUri, source.token) const title = await getAssetsNames(
[did],
if (!ddo) return config.metadataCacheUri,
const { attributes } = ddo.findServiceByType('metadata') source.token
setAssetTitle(attributes.main.name) )
setAssetTitle(title[did])
} }
!ddo && did && getDDO() !ddo && did && getAssetName()
return () => { return () => {
console.log('canceled?') console.log('canceled?')

View File

@ -69,20 +69,3 @@
width: auto; width: auto;
font-size: var(--font-size-mini); font-size: var(--font-size-mini);
} }
.icon {
fill: var(--brand-grey-light);
width: 1.1em;
height: 1.1em;
vertical-align: baseline;
margin-bottom: -0.2em;
display: inline-block;
}
.typeLabel {
display: inline-block;
text-transform: uppercase;
border-right: 1px solid var(--border-color);
padding-right: calc(var(--spacer) / 3.5);
margin-right: calc(var(--spacer) / 4);
}

View File

@ -8,8 +8,7 @@ import removeMarkdown from 'remove-markdown'
import Publisher from '../atoms/Publisher' import Publisher from '../atoms/Publisher'
import { useMetadata } from '@oceanprotocol/react' import { useMetadata } from '@oceanprotocol/react'
import Time from '../atoms/Time' import Time from '../atoms/Time'
import { ReactComponent as Compute } from '../../images/compute.svg' import AssetType from '../atoms/AssetType'
import { ReactComponent as Download } from '../../images/download.svg'
declare type AssetTeaserProps = { declare type AssetTeaserProps = {
ddo: DDO ddo: DDO
@ -20,7 +19,8 @@ const AssetTeaser: React.FC<AssetTeaserProps> = ({ ddo }: AssetTeaserProps) => {
const { attributes } = ddo.findServiceByType('metadata') const { attributes } = ddo.findServiceByType('metadata')
const { name, type } = attributes.main const { name, type } = attributes.main
const { dataTokenInfo } = ddo const { dataTokenInfo } = ddo
const accessType = ddo.service[1].type const isCompute = Boolean(ddo?.findServiceByType('compute'))
const accessType = isCompute ? 'compute' : 'access'
return ( return (
<article className={`${styles.teaser} ${styles[type]}`}> <article className={`${styles.teaser} ${styles[type]}`}>
@ -33,20 +33,11 @@ const AssetTeaser: React.FC<AssetTeaserProps> = ({ ddo }: AssetTeaserProps) => {
<Publisher account={owner} minimal className={styles.publisher} /> <Publisher account={owner} minimal className={styles.publisher} />
</header> </header>
<aside className={styles.typeDetails}> <AssetType
<div className={styles.typeLabel}> type={type}
{type === 'dataset' ? 'data set' : 'algorithm'} accessType={accessType}
</div> className={styles.typeDetails}
{accessType === 'access' ? ( />
<Download
role="img"
aria-label="Download"
className={styles.icon}
/>
) : (
<Compute role="img" aria-label="Compute" className={styles.icon} />
)}
</aside>
<div className={styles.content}> <div className={styles.content}>
<Dotdotdot tagName="p" clamp={3}> <Dotdotdot tagName="p" clamp={3}>

View File

@ -7,7 +7,7 @@
border-radius: var(--border-radius); border-radius: var(--border-radius);
padding: calc(var(--spacer) / 4); padding: calc(var(--spacer) / 4);
white-space: nowrap; white-space: nowrap;
background: none; background: var(--background-content);
margin: 0; margin: 0;
transition: border 0.2s ease-out; transition: border 0.2s ease-out;
cursor: pointer; cursor: pointer;

View File

@ -17,6 +17,7 @@ import Input from '../../atoms/Input'
import Alert from '../../atoms/Alert' import Alert from '../../atoms/Alert'
import { useSiteMetadata } from '../../../hooks/useSiteMetadata' import { useSiteMetadata } from '../../../hooks/useSiteMetadata'
import checkPreviousOrder from '../../../utils/checkPreviousOrder' import checkPreviousOrder from '../../../utils/checkPreviousOrder'
import { useAsset } from '../../../providers/Asset'
export default function Compute({ export default function Compute({
ddo, ddo,
@ -29,6 +30,7 @@ export default function Compute({
}): ReactElement { }): ReactElement {
const { marketFeeAddress } = useSiteMetadata() const { marketFeeAddress } = useSiteMetadata()
const { type } = useAsset()
const { ocean, accountId } = useOcean() const { ocean, accountId } = useOcean()
const { compute, isLoading, computeStepText, computeError } = useCompute() const { compute, isLoading, computeStepText, computeError } = useCompute()
const { buyDT, dtSymbol } = usePricing(ddo) const { buyDT, dtSymbol } = usePricing(ddo)
@ -129,16 +131,29 @@ export default function Compute({
</div> </div>
</div> </div>
<Input {type === 'algorithm' ? (
type="select" <Input
name="algorithm" type="select"
label="Select image to run the algorithm" name="data"
placeholder="" label="Select dataset for the algorithm"
size="small" placeholder=""
value={computeType} size="small"
options={computeOptions.map((x) => x.name)} value="dataset-1"
onChange={handleSelectChange} options={['dataset-1', 'dataset-2', 'dataset-3'].map((x) => x)}
/> onChange={handleSelectChange}
/>
) : (
<Input
type="select"
name="algorithm"
label="Select image to run the algorithm"
placeholder=""
size="small"
value={computeType}
options={computeOptions.map((x) => x.name)}
onChange={handleSelectChange}
/>
)}
<Dropzone multiple={false} handleOnDrop={onDrop} /> <Dropzone multiple={false} handleOnDrop={onDrop} />
<div className={styles.actions}> <div className={styles.actions}>

View File

@ -48,7 +48,7 @@ export default function Consume({
const { marketFeeAddress } = useSiteMetadata() const { marketFeeAddress } = useSiteMetadata()
const [hasPreviousOrder, setHasPreviousOrder] = useState(false) const [hasPreviousOrder, setHasPreviousOrder] = useState(false)
const [previousOrderId, setPreviousOrderId] = useState<string>() const [previousOrderId, setPreviousOrderId] = useState<string>()
const { isInPurgatory, price } = useAsset() const { isInPurgatory, price, type } = useAsset()
const { buyDT, pricingStepText, pricingError, pricingIsLoading } = usePricing( const { buyDT, pricingStepText, pricingError, pricingIsLoading } = usePricing(
ddo ddo
) )
@ -158,17 +158,10 @@ export default function Consume({
<File file={file} /> <File file={file} />
</div> </div>
<div className={styles.pricewrapper}> <div className={styles.pricewrapper}>
{isConsumable ? ( <Price ddo={ddo} conversion />
<Price ddo={ddo} conversion />
) : (
<div className={styles.help}>
There is not enough liquidity in the pool to buy this data set.
</div>
)}
{!isInPurgatory && <PurchaseButton />} {!isInPurgatory && <PurchaseButton />}
</div> </div>
</div> </div>
<footer className={styles.feedback}> <footer className={styles.feedback}>
<Web3Feedback isBalanceSufficient={isBalanceSufficient} /> <Web3Feedback isBalanceSufficient={isBalanceSufficient} />
</footer> </footer>

View File

@ -6,7 +6,15 @@ import Publisher from '../../atoms/Publisher'
import { useAsset } from '../../../providers/Asset' import { useAsset } from '../../../providers/Asset'
export default function MetaFull(): ReactElement { export default function MetaFull(): ReactElement {
const { ddo, metadata, isInPurgatory } = useAsset() const { ddo, metadata, isInPurgatory, type } = useAsset()
function DockerImage() {
const algorithmContainer = ddo.findServiceByType('metadata').attributes.main
.algorithm.container
const { image } = algorithmContainer
const { tag } = algorithmContainer
return <span>{`${image}:${tag}`}</span>
}
return ( return (
<div className={styles.metaFull}> <div className={styles.metaFull}>
@ -17,6 +25,9 @@ export default function MetaFull(): ReactElement {
title="Owner" title="Owner"
content={<Publisher account={ddo?.publicKey[0].owner} />} content={<Publisher account={ddo?.publicKey[0].owner} />}
/> />
{type === 'algorithm' && (
<MetaItem title="Docker Image" content={<DockerImage />} />
)}
{/* <MetaItem {/* <MetaItem
title="Data Created" title="Data Created"
content={<Time date={metadata?.main.dateCreated} />} content={<Time date={metadata?.main.dateCreated} />}

View File

@ -9,5 +9,17 @@
.date { .date {
font-size: var(--font-size-mini); font-size: var(--font-size-mini);
margin-top: calc(var(--spacer) / 2); }
.typeAndDate {
margin-top: calc(var(--spacer) / 2);
display: flex;
}
.typeDetails {
border-right: 1px solid var(--border-color);
padding-right: calc(var(--spacer) / 3.5);
margin-right: calc(var(--spacer) / 4);
width: auto;
font-size: var(--font-size-mini);
} }

View File

@ -5,10 +5,13 @@ import EtherscanLink from '../../atoms/EtherscanLink'
import Publisher from '../../atoms/Publisher' import Publisher from '../../atoms/Publisher'
import Time from '../../atoms/Time' import Time from '../../atoms/Time'
import styles from './MetaMain.module.css' import styles from './MetaMain.module.css'
import AssetType from '../../atoms/AssetType'
export default function MetaMain(): ReactElement { export default function MetaMain(): ReactElement {
const { ddo, owner } = useAsset() const { ddo, owner, type } = useAsset()
const { networkId } = useOcean() const { networkId } = useOcean()
const isCompute = Boolean(ddo?.findServiceByType('compute'))
const accessType = isCompute ? 'compute' : 'access'
return ( return (
<aside className={styles.meta}> <aside className={styles.meta}>
@ -20,15 +23,22 @@ export default function MetaMain(): ReactElement {
<div> <div>
Published By <Publisher account={owner} /> Published By <Publisher account={owner} />
</div> </div>
<p className={styles.date}> <div className={styles.typeAndDate}>
<Time date={ddo?.created} relative /> <AssetType
{ddo?.created !== ddo?.updated && ( type={type}
<> accessType={accessType}
{' — '} className={styles.typeDetails}
updated <Time date={ddo?.updated} relative /> />
</> <p className={styles.date}>
)} <Time date={ddo?.created} relative />
</p> {ddo?.created !== ddo?.updated && (
<>
{' — '}
updated <Time date={ddo?.updated} relative />
</>
)}
</p>
</div>
</aside> </aside>
) )
} }

View File

@ -1,7 +1,12 @@
/* .filterList { .filterList,
display: inline-flex; div.filterList {
float: left; white-space: normal;
} */ margin-bottom: 0;
}
.filter {
display: inline-block;
}
.filter, .filter,
button.filter, button.filter,
@ -9,14 +14,14 @@ button.filter,
.filter:active, .filter:active,
.filter:focus { .filter:focus {
border: 1px solid var(--border-color); border: 1px solid var(--border-color);
text-transform: uppercase;
border-radius: var(--border-radius); border-radius: var(--border-radius);
margin-right: calc(var(--spacer) / 6); margin-right: calc(var(--spacer) / 6);
margin-bottom: calc(var(--spacer) / 6);
color: var(--color-secondary); color: var(--color-secondary);
background: var(--background-body); background: var(--background-content);
/* the only thing not possible to overwrite button style="text" with more specifity of selectors, so sledgehammer */ /* the only thing not possible to overwrite button style="text" with more specifity of selectors, so sledgehammer */
padding: calc(var(--spacer) / 5) !important; padding: calc(var(--spacer) / 6) !important;
} }
.filter:hover, .filter:hover,
@ -32,6 +37,24 @@ button.filter,
border-color: var(--background-body); border-color: var(--background-body);
} }
.filter.selected::after {
content: '✕';
margin-left: calc(var(--spacer) / 6);
color: var(--background-body);
}
.filterList:first-of-type { .filterList:first-of-type {
margin-bottom: calc(var(--spacer) / 6); margin-bottom: calc(var(--spacer) / 6);
} }
.showClear {
display: inline-flex;
text-transform: capitalize;
color: var(--color-secondary);
font-weight: var(--font-weight-base);
margin-left: calc(var(--spacer) / 6);
}
.hideClear {
display: none !important;
}

View File

@ -1,4 +1,4 @@
import React, { ReactElement } from 'react' import React, { ReactElement, useEffect, useState } from 'react'
import { useNavigate } from '@reach/router' import { useNavigate } from '@reach/router'
import styles from './filterPrice.module.css' import styles from './filterPrice.module.css'
import classNames from 'classnames/bind' import classNames from 'classnames/bind'
@ -11,22 +11,22 @@ import Button from '../../atoms/Button'
const cx = classNames.bind(styles) const cx = classNames.bind(styles)
const filterItemsPrice = [ const clearFilters = [{ display: 'Clear', value: '' }]
{ display: 'all', value: undefined },
const priceFilterItems = [
{ display: 'fixed price', value: FilterByPriceOptions.Fixed }, { display: 'fixed price', value: FilterByPriceOptions.Fixed },
{ display: 'dynamic price', value: FilterByPriceOptions.Dynamic } { display: 'dynamic price', value: FilterByPriceOptions.Dynamic }
] ]
const filterItemsType = [ const serviceFilterItems = [
{ display: 'all', value: undefined }, { display: 'data sets', value: FilterByTypeOptions.Data },
{ display: 'algorithms', value: FilterByTypeOptions.Algorithm }, { display: 'algorithms', value: FilterByTypeOptions.Algorithm }
{ display: 'data sets', value: FilterByTypeOptions.Data }
] ]
export default function FilterPrice({ export default function FilterPrice({
priceType, priceType,
setPriceType,
serviceType, serviceType,
setPriceType,
setServiceType setServiceType
}: { }: {
priceType: string priceType: string
@ -36,7 +36,10 @@ export default function FilterPrice({
}): ReactElement { }): ReactElement {
const navigate = useNavigate() const navigate = useNavigate()
async function applyFilter(filterBy: string) { const [priceSelections, setPriceSelections] = useState<string[]>([])
const [serviceSelections, setServiceSelections] = useState<string[]>([])
async function applyPriceFilter(filterBy: string) {
let urlLocation = await addExistingParamsToUrl(location, 'priceType') let urlLocation = await addExistingParamsToUrl(location, 'priceType')
if (filterBy) { if (filterBy) {
urlLocation = `${urlLocation}&priceType=${filterBy}` urlLocation = `${urlLocation}&priceType=${filterBy}`
@ -45,59 +48,141 @@ export default function FilterPrice({
navigate(urlLocation) navigate(urlLocation)
} }
async function applyTypeFilter(filterBy: string) { async function applyServiceFilter(filterBy: string) {
let urlLocation = await addExistingParamsToUrl(location, 'serviceType') let urlLocation = await addExistingParamsToUrl(location, 'serviceType')
if (filterBy) { if (filterBy && location.search.indexOf('&serviceType') === -1) {
urlLocation = `${urlLocation}&serviceType=${filterBy}` urlLocation = `${urlLocation}&serviceType=${filterBy}`
} }
setServiceType(filterBy) setServiceType(filterBy)
navigate(urlLocation) navigate(urlLocation)
} }
async function handleSelectedFilter(isSelected: boolean, value: string) {
if (
value === FilterByPriceOptions.Fixed ||
value === FilterByPriceOptions.Dynamic
) {
if (isSelected) {
if (priceSelections.length > 1) {
// both selected -> select the other one
const otherValue = priceFilterItems.find((p) => p.value !== value)
.value
await applyPriceFilter(otherValue)
} else {
// only the current one selected -> deselect it
await applyPriceFilter(undefined)
}
} else {
if (priceSelections.length > 0) {
// one already selected -> both selected
await applyPriceFilter(FilterByPriceOptions.All)
setPriceSelections(priceFilterItems.map((p) => p.value))
} else {
// none selected -> select
await applyPriceFilter(value)
setPriceSelections([value])
}
}
} else {
if (isSelected) {
if (serviceSelections.length > 1) {
const otherValue = serviceFilterItems.find((p) => p.value !== value)
.value
await applyServiceFilter(otherValue)
setServiceSelections([otherValue])
} else {
await applyServiceFilter(undefined)
}
} else {
if (serviceSelections.length) {
await applyServiceFilter(undefined)
setServiceSelections(serviceFilterItems.map((p) => p.value))
} else {
await applyServiceFilter(value)
setServiceSelections([value])
}
}
}
}
async function applyClearFilter() {
let urlLocation = await addExistingParamsToUrl(
location,
'priceType',
'serviceType'
)
urlLocation = `${urlLocation}`
setServiceSelections([])
setPriceSelections([])
setPriceType(undefined)
setServiceType(undefined)
navigate(urlLocation)
}
return ( return (
<div> <div className={styles.filterList}>
<div className={styles.filterList}> {priceFilterItems.map((e, index) => {
{filterItemsType.map((e, index) => { const isPriceSelected =
const filter = cx({ e.value === priceType || priceSelections.includes(e.value)
[styles.selected]: e.value === serviceType, const selectFilter = cx({
[styles.filter]: true [styles.selected]: isPriceSelected,
}) [styles.filter]: true
return ( })
<Button return (
size="small" <Button
style="text" size="small"
key={index} style="text"
className={filter} key={index}
onClick={async () => { className={selectFilter}
await applyTypeFilter(e.value) onClick={async () => {
}} handleSelectedFilter(isPriceSelected, e.value)
> }}
{e.display} >
</Button> {e.display}
) </Button>
})} )
</div> })}
<div className={styles.filterList}> {serviceFilterItems.map((e, index) => {
{filterItemsPrice.map((e, index) => { const isServiceSelected =
const filter = cx({ e.value === serviceType || serviceSelections.includes(e.value)
[styles.selected]: e.value === priceType, const selectFilter = cx({
[styles.filter]: true [styles.selected]: isServiceSelected,
}) [styles.filter]: true
return ( })
<Button return (
size="small" <Button
style="text" size="small"
key={index} style="text"
className={filter} key={index}
onClick={async () => { className={selectFilter}
await applyFilter(e.value) onClick={async () => {
}} handleSelectedFilter(isServiceSelected, e.value)
> }}
{e.display} >
</Button> {e.display}
) </Button>
})} )
</div> })}
{clearFilters.map((e, index) => {
const showClear =
priceSelections.length > 0 || serviceSelections.length > 0
return (
<Button
size="small"
style="text"
key={index}
className={showClear ? styles.showClear : styles.hideClear}
onClick={async () => {
applyClearFilter()
}}
>
{e.display}
</Button>
)
})}
</div> </div>
) )
} }

View File

@ -34,7 +34,7 @@ export default function SearchPage({
const [queryResult, setQueryResult] = useState<QueryResult>() const [queryResult, setQueryResult] = useState<QueryResult>()
const [loading, setLoading] = useState<boolean>() const [loading, setLoading] = useState<boolean>()
const [price, setPriceType] = useState<string>(priceType as string) const [price, setPriceType] = useState<string>(priceType as string)
const [type, setType] = useState<string>(serviceType as string) const [service, setServiceType] = useState<string>(serviceType as string)
const [sortType, setSortType] = useState<string>(sort as string) const [sortType, setSortType] = useState<string>(sort as string)
const [sortDirection, setSortDirection] = useState<string>( const [sortDirection, setSortDirection] = useState<string>(
sortOrder as string sortOrder as string
@ -82,9 +82,9 @@ export default function SearchPage({
<div className={styles.row}> <div className={styles.row}>
<PriceFilter <PriceFilter
priceType={price} priceType={price}
serviceType={service}
setPriceType={setPriceType} setPriceType={setPriceType}
serviceType={type} setServiceType={setServiceType}
setServiceType={setType}
/> />
<Sort <Sort
sortType={sortType} sortType={sortType}
@ -92,6 +92,7 @@ export default function SearchPage({
setSortType={setSortType} setSortType={setSortType}
setSortDirection={setSortDirection} setSortDirection={setSortDirection}
setPriceType={setPriceType} setPriceType={setPriceType}
setServiceType={setServiceType}
/> />
</div> </div>
</div> </div>

View File

@ -1,11 +1,18 @@
.sortList { .sortList {
align-self: flex-end; padding: 0 calc(var(--spacer) / 10);
padding: calc(var(--spacer) / 10);
display: flex; display: flex;
align-items: center; align-items: center;
border-radius: var(--border-radius); border-radius: var(--border-radius);
border: 1px solid var(--border-color); border: 1px solid var(--border-color);
background: var(--background-body); background: var(--background-content);
overflow-y: auto;
}
@media (min-width: 40rem) {
.sortList {
align-self: flex-end;
overflow-y: unset;
}
} }
.sortLabel { .sortLabel {
@ -15,6 +22,7 @@
margin-right: calc(var(--spacer) / 1.5); margin-right: calc(var(--spacer) / 1.5);
text-transform: uppercase; text-transform: uppercase;
color: var(--color-secondary); color: var(--color-secondary);
font-size: var(--font-size-small);
} }
.sorted { .sorted {
@ -25,7 +33,7 @@
text-transform: capitalize; text-transform: capitalize;
border-radius: 0; border-radius: 0;
font-weight: var(--font-weight-base); font-weight: var(--font-weight-base);
background: var(--background-body); background: var(--background-content);
box-shadow: none; box-shadow: none;
} }

View File

@ -24,13 +24,15 @@ export default function Sort({
setSortType, setSortType,
sortDirection, sortDirection,
setSortDirection, setSortDirection,
setPriceType setPriceType,
setServiceType
}: { }: {
sortType: string sortType: string
setSortType: React.Dispatch<React.SetStateAction<string>> setSortType: React.Dispatch<React.SetStateAction<string>>
sortDirection: string sortDirection: string
setSortDirection: React.Dispatch<React.SetStateAction<string>> setSortDirection: React.Dispatch<React.SetStateAction<string>>
setPriceType: React.Dispatch<React.SetStateAction<string>> setPriceType: React.Dispatch<React.SetStateAction<string>>
setServiceType: React.Dispatch<React.SetStateAction<string>>
}): ReactElement { }): ReactElement {
const navigate = useNavigate() const navigate = useNavigate()
const directionArrow = String.fromCharCode( const directionArrow = String.fromCharCode(
@ -44,8 +46,6 @@ export default function Sort({
if (sortBy === SortTermOptions.Liquidity) { if (sortBy === SortTermOptions.Liquidity) {
urlLocation = `${urlLocation}&priceType=${FilterByPriceOptions.Dynamic}` urlLocation = `${urlLocation}&priceType=${FilterByPriceOptions.Dynamic}`
setPriceType(FilterByPriceOptions.Dynamic) setPriceType(FilterByPriceOptions.Dynamic)
} else {
setPriceType(undefined)
} }
setSortType(sortBy) setSortType(sortBy)
} else if (direction) { } else if (direction) {

View File

@ -28,7 +28,8 @@ type SortValueOptions = typeof SortValueOptions[keyof typeof SortValueOptions]
export const FilterByPriceOptions = { export const FilterByPriceOptions = {
Fixed: 'exchange', Fixed: 'exchange',
Dynamic: 'pool' Dynamic: 'pool',
All: 'all'
} as const } as const
type FilterByPriceOptions = typeof FilterByPriceOptions[keyof typeof FilterByPriceOptions] type FilterByPriceOptions = typeof FilterByPriceOptions[keyof typeof FilterByPriceOptions]
@ -38,12 +39,20 @@ export const FilterByTypeOptions = {
} as const } as const
type FilterByTypeOptions = typeof FilterByTypeOptions[keyof typeof FilterByTypeOptions] type FilterByTypeOptions = typeof FilterByTypeOptions[keyof typeof FilterByTypeOptions]
function addPriceFilterToQuerry(sortTerm: string, priceFilter: string): string { function addPriceFilterToQuery(sortTerm: string, priceFilter: string): string {
sortTerm = priceFilter if (priceFilter === FilterByPriceOptions.All) {
? sortTerm === '' sortTerm = priceFilter
? `price.type:${priceFilter}` ? sortTerm === ''
: `${sortTerm} AND price.type:${priceFilter}` ? `(price.type:${FilterByPriceOptions.Fixed} OR price.type:${FilterByPriceOptions.Dynamic})`
: sortTerm : `${sortTerm} AND (price.type:${FilterByPriceOptions.Dynamic} OR price.type:${FilterByPriceOptions.Fixed})`
: sortTerm
} else {
sortTerm = priceFilter
? sortTerm === ''
? `price.type:${priceFilter}`
: `${sortTerm} AND price.type:${priceFilter}`
: sortTerm
}
return sortTerm return sortTerm
} }
@ -89,9 +98,9 @@ export function getSearchQuery(
? // eslint-disable-next-line no-useless-escape ? // eslint-disable-next-line no-useless-escape
`(service.attributes.additionalInformation.categories:\"${categories}\")` `(service.attributes.additionalInformation.categories:\"${categories}\")`
: text || '' : text || ''
searchTerm = addPriceFilterToQuerry(searchTerm, priceType)
searchTerm = addTypeFilterToQuery(searchTerm, serviceType) searchTerm = addTypeFilterToQuery(searchTerm, serviceType)
console.log('search', searchTerm, serviceType) searchTerm = addPriceFilterToQuery(searchTerm, priceType)
return { return {
page: Number(page) || 1, page: Number(page) || 1,
offset: Number(offset) || 21, offset: Number(offset) || 21,

View File

@ -25,7 +25,7 @@
/* Only use these vars for most color referencing for easy light/dark mode */ /* Only use these vars for most color referencing for easy light/dark mode */
--font-color-text: #41474e; --font-color-text: #41474e;
--font-color-heading: #141414; --font-color-heading: #141414;
--background-body: #fafafa; --background-body: #fcfcfc;
--background-body-transparent: rgba(255, 255, 255, 0.8); --background-body-transparent: rgba(255, 255, 255, 0.8);
--background-content: #fff; --background-content: #fff;
--background-highlight: #f7f7f7; --background-highlight: #f7f7f7;

View File

@ -27,7 +27,7 @@ export default function PageGatsbySearch(props: PageProps): ReactElement {
(totalResults > 1 ? ' results' : ' result') + (totalResults > 1 ? ' results' : ' result') +
' for ' + ' for ' +
searchValue searchValue
: totalResults + ' datasets' : totalResults + ' results'
: 'Searching...' : 'Searching...'
}` }`

View File

@ -7,7 +7,7 @@ import React, {
useCallback, useCallback,
ReactNode ReactNode
} from 'react' } from 'react'
import { Logger, DDO, BestPrice } from '@oceanprotocol/lib' import { Logger, DDO, BestPrice, MetadataMain } from '@oceanprotocol/lib'
import { PurgatoryData } from '@oceanprotocol/lib/dist/node/ddo/interfaces/PurgatoryData' import { PurgatoryData } from '@oceanprotocol/lib/dist/node/ddo/interfaces/PurgatoryData'
import { getDataTokenPrice, useOcean } from '@oceanprotocol/react' import { getDataTokenPrice, useOcean } from '@oceanprotocol/react'
import getAssetPurgatoryData from '../utils/purgatory' import getAssetPurgatoryData from '../utils/purgatory'
@ -25,6 +25,7 @@ interface AssetProviderValue {
title: string | undefined title: string | undefined
owner: string | undefined owner: string | undefined
price: BestPrice | undefined price: BestPrice | undefined
type: MetadataMain['type'] | undefined
error?: string error?: string
refreshInterval: number refreshInterval: number
refreshDdo: (token?: CancelToken) => Promise<void> refreshDdo: (token?: CancelToken) => Promise<void>
@ -52,6 +53,7 @@ function AssetProvider({
const [price, setPrice] = useState<BestPrice>() const [price, setPrice] = useState<BestPrice>()
const [owner, setOwner] = useState<string>() const [owner, setOwner] = useState<string>()
const [error, setError] = useState<string>() const [error, setError] = useState<string>()
const [type, setType] = useState<MetadataMain['type']>()
const refreshPrice = useCallback(async () => { const refreshPrice = useCallback(async () => {
if ( if (
@ -160,6 +162,7 @@ function AssetProvider({
const { attributes } = ddo.findServiceByType('metadata') const { attributes } = ddo.findServiceByType('metadata')
setMetadata((attributes as unknown) as MetadataMarket) setMetadata((attributes as unknown) as MetadataMarket)
setTitle(attributes?.main.name) setTitle(attributes?.main.name)
setType(attributes.main.type)
setOwner(ddo.publicKey[0].owner) setOwner(ddo.publicKey[0].owner)
setIsInPurgatory(ddo.isInPurgatory === 'true') setIsInPurgatory(ddo.isInPurgatory === 'true')
@ -184,6 +187,7 @@ function AssetProvider({
title, title,
owner, owner,
price, price,
type,
error, error,
isInPurgatory, isInPurgatory,
purgatoryData, purgatoryData,

View File

@ -73,3 +73,27 @@ export async function retrieveDDO(
} }
} }
} }
export async function getAssetsNames(
didList: string[] | DID[],
metadataCacheUri: string,
cancelToken: CancelToken
): Promise<Record<string, string>> {
try {
const response: AxiosResponse<Record<string, string>> = await axios.post(
`${metadataCacheUri}/api/v1/aquarius/assets/names`,
{
didList,
cancelToken
}
)
if (!response || response.status !== 200 || !response.data) return
return response.data
} catch (error) {
if (axios.isCancel(error)) {
Logger.log(error.message)
} else {
Logger.error(error.message)
}
}
}

View File

@ -5,7 +5,7 @@ import { Logger } from '@oceanprotocol/lib'
// https://docs.3box.io/api/rest-api // https://docs.3box.io/api/rest-api
const apiUri = 'https://3box.oceanprotocol.com' const apiUri = 'https://3box.oceanprotocol.com'
const ipfsUrl = 'https://ipfs.oceanprotocol.com' const ipfsUrl = 'https://dweb.link'
function decodeProof(proofJWT: string) { function decodeProof(proofJWT: string) {
if (!proofJWT) return if (!proofJWT) return