Refactor aquarius calls (#917)

* aquarius refactor

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

* fix highest liquidity

Signed-off-by: mihaisc <mihai@oceanprotocol.com>

* fix

* update search

Signed-off-by: mihaisc <mihai@oceanprotocol.com>

* remove test code

Signed-off-by: mihaisc <mihai@oceanprotocol.com>

* remove logs&unused dep

* remove old types

* fix bookmarks

* fix downloaded assets

* fix published list

* fix profile

* fix compute history

* fix compute

* fix edit compute

* remove old commented code
This commit is contained in:
mihaisc 2021-10-21 00:24:00 -07:00 committed by GitHub
parent fdcf72b067
commit cef0969065
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 645 additions and 526 deletions

View File

@ -235,7 +235,6 @@ Wenn du Fragen zu Purgatory hast oder wenn du kein GitHub-Konto besitzt und möc
Du hast das Recht, deine personenbezogenen Daten in einem strukturierten, gängigen und maschinenlesbaren Format zu erhalten. Zusätzlich hast du das Recht, diese Daten ungehindert an einen anderen Verantwortlichen zu übermitteln, sofern die in Art. 20 DSGVO definierten Voraussetzungen zutreffen. Du hast das Recht, deine personenbezogenen Daten in einem strukturierten, gängigen und maschinenlesbaren Format zu erhalten. Zusätzlich hast du das Recht, diese Daten ungehindert an einen anderen Verantwortlichen zu übermitteln, sofern die in Art. 20 DSGVO definierten Voraussetzungen zutreffen.
Sie können von Ihrem Recht auf Datenübertragbarkeit Gebrauch machen, indem Sie sich mit uns in Verbindung setzen. Sie können von Ihrem Recht auf Datenübertragbarkeit Gebrauch machen, indem Sie sich mit uns in Verbindung setzen.
## 7.6 Widerspruchsrecht (Art. 21 GDPR) ## 7.6 Widerspruchsrecht (Art. 21 GDPR)
Du hast das Recht, aus Gründen, die sich aus deiner besonderen Situation ergeben, gegen die Verarbeitung deiner personenbezogenen Daten Widerspruch einzulegen, wenn wir die Verarbeitung auf die Wahrung unseres berechtigten Interessens stützen (Art. 6(1)(f) GDPR). Wenn du Widerspruch einlegst, werden wir deine personenbezogenen Daten nicht mehr verarbeiten, es sei denn, wir können zwingende schutzwürdige Gründe für die Verarbeitung nachweisen, die deine Rechte, Freiheiten und Interessen überwiegen, oder wenn die Verarbeitung zur Begründung, Ausübung oder Verteidigung von Rechtsansprüchen erforderlich ist. Du hast das Recht, aus Gründen, die sich aus deiner besonderen Situation ergeben, gegen die Verarbeitung deiner personenbezogenen Daten Widerspruch einzulegen, wenn wir die Verarbeitung auf die Wahrung unseres berechtigten Interessens stützen (Art. 6(1)(f) GDPR). Wenn du Widerspruch einlegst, werden wir deine personenbezogenen Daten nicht mehr verarbeiten, es sei denn, wir können zwingende schutzwürdige Gründe für die Verarbeitung nachweisen, die deine Rechte, Freiheiten und Interessen überwiegen, oder wenn die Verarbeitung zur Begründung, Ausübung oder Verteidigung von Rechtsansprüchen erforderlich ist.

View File

@ -235,7 +235,6 @@ Si vous avez des questions sur Purgatory ou si vous n&#39;avez pas de compte Git
Vous avez le droit de recevoir vos données personnelles dans un format structuré, couramment utilisé et lisible par machine. En outre, vous avez le droit de transmettre ces données à un autre responsable du traitement sans entrave, lorsque les fondements juridiques définis à l&#39;article 20 du RGPD s&#39;appliquent. Vous avez le droit de recevoir vos données personnelles dans un format structuré, couramment utilisé et lisible par machine. En outre, vous avez le droit de transmettre ces données à un autre responsable du traitement sans entrave, lorsque les fondements juridiques définis à l&#39;article 20 du RGPD s&#39;appliquent.
Vous pouvez faire usage de votre droit à la portabilité des données en nous contactant. Vous pouvez faire usage de votre droit à la portabilité des données en nous contactant.
## 7.6 Droit d&#39;opposition (art. 21 du RGPD) ## 7.6 Droit d&#39;opposition (art. 21 du RGPD)
Pour des motifs liés à votre situation particulière, vous avez le droit de vous opposer au traitement de vos données personnelles lorsque nous avons basé le traitement sur des intérêts légitimes (art. 6(1)(f) du RGPD). Si vous vous y opposez, Ocean ne traitera plus vos données personnelles à moins que nous puissions démontrer des motifs légitimes impérieux pour le traitement, outrepassant vos droits, libertés et intérêts, ou si le traitement est nécessaire pour établir, exercer ou défendre des réclamations légales. Pour des motifs liés à votre situation particulière, vous avez le droit de vous opposer au traitement de vos données personnelles lorsque nous avons basé le traitement sur des intérêts légitimes (art. 6(1)(f) du RGPD). Si vous vous y opposez, Ocean ne traitera plus vos données personnelles à moins que nous puissions démontrer des motifs légitimes impérieux pour le traitement, outrepassant vos droits, libertés et intérêts, ou si le traitement est nécessaire pour établir, exercer ou défendre des réclamations légales.

View File

@ -1,5 +1,5 @@
import { useUserPreferences } from '../../providers/UserPreferences' import { useUserPreferences } from '../../providers/UserPreferences'
import React, { ReactElement, useEffect, useState } from 'react' import React, { ReactElement, useCallback, useEffect, useState } from 'react'
import Table from '../atoms/Table' import Table from '../atoms/Table'
import { Logger } from '@oceanprotocol/lib' import { Logger } from '@oceanprotocol/lib'
import Price from '../atoms/Price' import Price from '../atoms/Price'
@ -7,22 +7,9 @@ import Tooltip from '../atoms/Tooltip'
import AssetTitle from './AssetListTitle' import AssetTitle from './AssetListTitle'
import { retrieveDDOListByDIDs } from '../../utils/aquarius' import { retrieveDDOListByDIDs } from '../../utils/aquarius'
import { getAssetsBestPrices, AssetListPrices } from '../../utils/subgraph' import { getAssetsBestPrices, AssetListPrices } from '../../utils/subgraph'
import axios, { CancelToken } from 'axios'
import { useSiteMetadata } from '../../hooks/useSiteMetadata' import { useSiteMetadata } from '../../hooks/useSiteMetadata'
import { useCancelToken } from '../../hooks/useCancelToken' import { useCancelToken } from '../../hooks/useCancelToken'
import { CancelToken } from 'axios'
async function getAssetsBookmarked(
bookmarks: string[],
chainIds: number[],
cancelToken: CancelToken
) {
try {
const result = await retrieveDDOListByDIDs(bookmarks, chainIds, cancelToken)
return result
} catch (error) {
Logger.error(error.message)
}
}
const columns = [ const columns = [
{ {
@ -62,6 +49,27 @@ export default function Bookmarks(): ReactElement {
const [isLoading, setIsLoading] = useState<boolean>() const [isLoading, setIsLoading] = useState<boolean>()
const { chainIds } = useUserPreferences() const { chainIds } = useUserPreferences()
const newCancelToken = useCancelToken() const newCancelToken = useCancelToken()
const getAssetsBookmarked = useCallback(
async (
bookmarks: string[],
chainIds: number[],
cancelToken: CancelToken
) => {
try {
const result = await retrieveDDOListByDIDs(
bookmarks,
chainIds,
cancelToken
)
return result
} catch (error) {
Logger.error(error.message)
}
},
[]
)
useEffect(() => { useEffect(() => {
if (!appConfig?.metadataCacheUri || bookmarks === []) return if (!appConfig?.metadataCacheUri || bookmarks === []) return
@ -90,7 +98,13 @@ export default function Bookmarks(): ReactElement {
setIsLoading(false) setIsLoading(false)
} }
init() init()
}, [appConfig?.metadataCacheUri, bookmarks, chainIds, newCancelToken]) }, [
appConfig?.metadataCacheUri,
bookmarks,
chainIds,
getAssetsBookmarked,
newCancelToken
])
return ( return (
<Table <Table

View File

@ -15,6 +15,8 @@ import { useWeb3 } from '../../../../providers/Web3'
import { usePricing } from '../../../../hooks/usePricing' import { usePricing } from '../../../../hooks/usePricing'
import { useAsset } from '../../../../providers/Asset' import { useAsset } from '../../../../providers/Asset'
import { import {
generateBaseQuery,
getFilterTerm,
queryMetadata, queryMetadata,
transformDDOToAssetSelection transformDDOToAssetSelection
} from '../../../../utils/aquarius' } from '../../../../utils/aquarius'
@ -27,7 +29,6 @@ import {
ComputeAlgorithm, ComputeAlgorithm,
ComputeOutput ComputeOutput
} from '@oceanprotocol/lib/dist/node/ocean/interfaces/Compute' } from '@oceanprotocol/lib/dist/node/ocean/interfaces/Compute'
import { SearchQuery } from '@oceanprotocol/lib/dist/node/metadatacache/MetadataCache'
import axios from 'axios' import axios from 'axios'
import FormStartComputeDataset from './FormComputeDataset' import FormStartComputeDataset from './FormComputeDataset'
import styles from './index.module.css' import styles from './index.module.css'
@ -42,6 +43,9 @@ import ComputeJobs from '../../../pages/Profile/History/ComputeJobs'
import { BestPrice } from '../../../../models/BestPrice' import { BestPrice } from '../../../../models/BestPrice'
import { useCancelToken } from '../../../../hooks/useCancelToken' import { useCancelToken } from '../../../../hooks/useCancelToken'
import { useIsMounted } from '../../../../hooks/useIsMounted' import { useIsMounted } from '../../../../hooks/useIsMounted'
import { BaseQueryParams } from '../../../../models/aquarius/BaseQueryParams'
import { SortTermOptions } from '../../../../models/SortAndFilters'
import { SearchQuery } from '../../../../models/aquarius/SearchQuery'
const SuccessAction = () => ( const SuccessAction = () => (
<Button style="text" to="/profile?defaultTab=ComputeJobs" size="small"> <Button style="text" to="/profile?defaultTab=ComputeJobs" size="small">
@ -133,23 +137,18 @@ export default function Compute({
trustedAlgorithmList: publisherTrustedAlgorithm[], trustedAlgorithmList: publisherTrustedAlgorithm[],
chainId?: number chainId?: number
): SearchQuery { ): SearchQuery {
let algoQuerry = '' const algorithmDidList = trustedAlgorithmList.map((x) => x.did)
trustedAlgorithmList.forEach((trusteAlgo) => {
algoQuerry += `id:"${trusteAlgo.did}" OR ` const baseParams = {
}) chainIds: [chainId],
if (trustedAlgorithmList.length >= 1) { sort: { sortBy: SortTermOptions.Created },
algoQuerry = algoQuerry.substring(0, algoQuerry.length - 3) filters: [
} getFilterTerm('service.attributes.main.type', 'algorithm'),
const algorithmQuery = getFilterTerm('id', algorithmDidList)
trustedAlgorithmList.length > 0 ? `(${algoQuerry}) AND` : `` ]
const query = { } as BaseQueryParams
query: {
query_string: { const query = generateBaseQuery(baseParams)
query: `${algorithmQuery} service.attributes.main.type:algorithm AND chainId:${chainId} -isInPurgatory:true`
}
},
sort: { created: 'desc' }
}
return query return query
} }

View File

@ -6,16 +6,19 @@ import { AssetSelectionAsset } from '../../../molecules/FormFields/AssetSelectio
import stylesIndex from './index.module.css' import stylesIndex from './index.module.css'
import styles from './FormEditMetadata.module.css' import styles from './FormEditMetadata.module.css'
import { import {
generateBaseQuery,
getFilterTerm,
queryMetadata, queryMetadata,
transformDDOToAssetSelection transformDDOToAssetSelection
} from '../../../../utils/aquarius' } from '../../../../utils/aquarius'
import { useAsset } from '../../../../providers/Asset' import { useAsset } from '../../../../providers/Asset'
import { ComputePrivacyForm } from '../../../../models/FormEditComputeDataset' import { ComputePrivacyForm } from '../../../../models/FormEditComputeDataset'
import { publisherTrustedAlgorithm as PublisherTrustedAlgorithm } from '@oceanprotocol/lib' import { publisherTrustedAlgorithm as PublisherTrustedAlgorithm } from '@oceanprotocol/lib'
import axios from 'axios'
import { useSiteMetadata } from '../../../../hooks/useSiteMetadata' import { useSiteMetadata } from '../../../../hooks/useSiteMetadata'
import FormActions from './FormActions' import FormActions from './FormActions'
import { useCancelToken } from '../../../../hooks/useCancelToken' import { useCancelToken } from '../../../../hooks/useCancelToken'
import { BaseQueryParams } from '../../../../models/aquarius/BaseQueryParams'
import { SortTermOptions } from '../../../../models/SortAndFilters'
export default function FormEditComputeDataset({ export default function FormEditComputeDataset({
data, data,
@ -37,14 +40,13 @@ export default function FormEditComputeDataset({
async function getAlgorithmList( async function getAlgorithmList(
publisherTrustedAlgorithms: PublisherTrustedAlgorithm[] publisherTrustedAlgorithms: PublisherTrustedAlgorithm[]
): Promise<AssetSelectionAsset[]> { ): Promise<AssetSelectionAsset[]> {
const query = { const baseParams = {
query: { chainIds: [ddo.chainId],
query_string: { sort: { sortBy: SortTermOptions.Created },
query: `service.attributes.main.type:algorithm AND chainId:${ddo.chainId} -isInPurgatory:true` filters: [getFilterTerm('service.attributes.main.type', 'algorithm')]
} } as BaseQueryParams
},
sort: { created: 'desc' } const query = generateBaseQuery(baseParams)
}
const querryResult = await queryMetadata(query, newCancelToken()) const querryResult = await queryMetadata(query, newCancelToken())
const datasetComputeService = ddo.findServiceByType('compute') const datasetComputeService = ddo.findServiceByType('compute')
const algorithmSelectionList = await transformDDOToAssetSelection( const algorithmSelectionList = await transformDDOToAssetSelection(

View File

@ -1,57 +1,47 @@
import React, { ReactElement, useEffect, useState } from 'react' import React, { ReactElement, useEffect, useState } from 'react'
import AssetList from '../organisms/AssetList' import AssetList from '../organisms/AssetList'
import { SearchQuery } from '@oceanprotocol/lib/dist/node/metadatacache/MetadataCache'
import Button from '../atoms/Button' import Button from '../atoms/Button'
import Bookmarks from '../molecules/Bookmarks' import Bookmarks from '../molecules/Bookmarks'
import { import {
queryMetadata, generateBaseQuery,
transformChainIdsListToQuery getFilterTerm,
queryMetadata
} from '../../utils/aquarius' } from '../../utils/aquarius'
import Permission from '../organisms/Permission' import Permission from '../organisms/Permission'
import { getHighestLiquidityDIDs } from '../../utils/subgraph' import { getHighestLiquidityDatatokens } from '../../utils/subgraph'
import { DDO, Logger } from '@oceanprotocol/lib' import { DDO, Logger } from '@oceanprotocol/lib'
import { useSiteMetadata } from '../../hooks/useSiteMetadata' import { useSiteMetadata } from '../../hooks/useSiteMetadata'
import { useUserPreferences } from '../../providers/UserPreferences' import { useUserPreferences } from '../../providers/UserPreferences'
import styles from './Home.module.css' import styles from './Home.module.css'
import { useIsMounted } from '../../hooks/useIsMounted' import { useIsMounted } from '../../hooks/useIsMounted'
import { useCancelToken } from '../../hooks/useCancelToken' import { useCancelToken } from '../../hooks/useCancelToken'
import { SearchQuery } from '../../models/aquarius/SearchQuery'
import { SortTermOptions } from '../../models/SortAndFilters'
import { BaseQueryParams } from '../../models/aquarius/BaseQueryParams'
import { PagedAssets } from '../../models/PagedAssets'
async function getQueryHighest( async function getQueryHighest(
chainIds: number[] chainIds: number[]
): Promise<[SearchQuery, string]> { ): Promise<[SearchQuery, string[]]> {
const [dids, didsLength] = await getHighestLiquidityDIDs(chainIds) const dtList = await getHighestLiquidityDatatokens(chainIds)
const queryHighest = { const baseQueryParams = {
size: didsLength > 0 ? didsLength : 1, chainIds,
query: { esPaginationOptions: {
query_string: { size: dtList.length > 0 ? dtList.length : 1
query: `${dids && `(${dids}) AND`}(${transformChainIdsListToQuery(
chainIds
)}) AND -isInPurgatory:true `,
fields: ['dataToken']
}
}
}
return [queryHighest, dids]
}
function getQueryLatest(chainIds: number[]): any {
return {
size: 9,
query: {
query_string: {
query: `(${transformChainIdsListToQuery(
chainIds
)}) AND -isInPurgatory:true `
}
}, },
sort: { created: 'desc' } filters: [getFilterTerm('dataToken', dtList)]
} } as BaseQueryParams
const queryHighest = generateBaseQuery(baseQueryParams)
return [queryHighest, dtList]
} }
function sortElements(items: DDO[], sorted: string[]) { function sortElements(items: DDO[], sorted: string[]) {
items.sort(function (a, b) { items.sort(function (a, b) {
return sorted.indexOf(a.dataToken) - sorted.indexOf(b.dataToken) return (
sorted.indexOf(a.dataToken.toLowerCase()) -
sorted.indexOf(b.dataToken.toLowerCase())
)
}) })
return items return items
} }
@ -65,7 +55,7 @@ function SectionQueryResult({
title: ReactElement | string title: ReactElement | string
query: SearchQuery query: SearchQuery
action?: ReactElement action?: ReactElement
queryData?: string queryData?: string[]
}) { }) {
const { chainIds } = useUserPreferences() const { chainIds } = useUserPreferences()
const [result, setResult] = useState<any>() const [result, setResult] = useState<any>()
@ -75,7 +65,7 @@ function SectionQueryResult({
useEffect(() => { useEffect(() => {
async function init() { async function init() {
if (chainIds.length === 0) { if (chainIds.length === 0) {
const result: any = { const result: PagedAssets = {
results: [], results: [],
page: 0, page: 0,
totalPages: 0, totalPages: 0,
@ -89,8 +79,7 @@ function SectionQueryResult({
const result = await queryMetadata(query, newCancelToken()) const result = await queryMetadata(query, newCancelToken())
if (!isMounted()) return if (!isMounted()) return
if (queryData && result?.totalResults > 0) { if (queryData && result?.totalResults > 0) {
const searchDIDs = queryData.split(' ') const sortedAssets = sortElements(result.results, queryData)
const sortedAssets = sortElements(result.results, searchDIDs)
const overflow = sortedAssets.length - 9 const overflow = sortedAssets.length - 9
sortedAssets.splice(sortedAssets.length - overflow, overflow) sortedAssets.splice(sortedAssets.length - overflow, overflow)
result.results = sortedAssets result.results = sortedAssets
@ -103,7 +92,7 @@ function SectionQueryResult({
} }
} }
init() init()
}, [isMounted, newCancelToken, query]) }, [chainIds.length, isMounted, newCancelToken, query, queryData])
return ( return (
<section className={styles.section}> <section className={styles.section}>
@ -119,13 +108,22 @@ function SectionQueryResult({
} }
export default function HomePage(): ReactElement { export default function HomePage(): ReactElement {
const [queryAndDids, setQueryAndDids] = useState<[SearchQuery, string]>() const [queryAndDids, setQueryAndDids] = useState<[SearchQuery, string[]]>()
const [queryLatest, setQueryLatest] = useState<SearchQuery>()
const { chainIds } = useUserPreferences() const { chainIds } = useUserPreferences()
useEffect(() => { useEffect(() => {
getQueryHighest(chainIds).then((results) => { getQueryHighest(chainIds).then((results) => {
setQueryAndDids(results) setQueryAndDids(results)
}) })
const baseParams = {
chainIds: chainIds,
esPaginationOptions: { size: 9 },
sort: { sortBy: SortTermOptions.Created }
} as BaseQueryParams
setQueryLatest(generateBaseQuery(baseParams))
}, [chainIds]) }, [chainIds])
return ( return (
@ -144,15 +142,17 @@ export default function HomePage(): ReactElement {
/> />
)} )}
<SectionQueryResult {queryLatest && (
title="Recently Published" <SectionQueryResult
query={getQueryLatest(chainIds)} title="Recently Published"
action={ query={queryLatest}
<Button style="text" to="/search?sort=created&sortOrder=desc"> action={
All data sets and algorithms <Button style="text" to="/search?sort=created&sortOrder=desc">
</Button> All data sets and algorithms
} </Button>
/> }
/>
)}
</> </>
</Permission> </Permission>
) )

View File

@ -5,7 +5,6 @@ import { useUserPreferences } from '../../../../providers/UserPreferences'
import { import {
getAccountLiquidityInOwnAssets, getAccountLiquidityInOwnAssets,
getAssetsBestPrices, getAssetsBestPrices,
getUserSales,
UserLiquidity, UserLiquidity,
calculateUserLiquidity calculateUserLiquidity
} from '../../../../utils/subgraph' } from '../../../../utils/subgraph'

View File

@ -4,8 +4,7 @@ import Time from '../../../atoms/Time'
import AssetTitle from '../../../molecules/AssetListTitle' import AssetTitle from '../../../molecules/AssetListTitle'
import NetworkName from '../../../atoms/NetworkName' import NetworkName from '../../../atoms/NetworkName'
import { useProfile } from '../../../../providers/Profile' import { useProfile } from '../../../../providers/Profile'
import { DownloadedAsset } from '../../../../utils/aquarius' import { DownloadedAsset } from '../../../../models/aquarius/DownloadedAsset'
const columns = [ const columns = [
{ {
name: 'Data Set', name: 'Data Set',

View File

@ -64,9 +64,9 @@ function Liquidity({ row, type }: { row: Asset; type: string }) {
price = price =
isValidNumber(row.poolShare.poolId.oceanReserve) && isValidNumber(row.poolShare.poolId.oceanReserve) &&
isValidNumber(row.poolShare.poolId.datatokenReserve) && isValidNumber(row.poolShare.poolId.datatokenReserve) &&
isValidNumber(row.poolShare.poolId.consumePrice) isValidNumber(row.poolShare.poolId.spotPrice)
? new Decimal(row.poolShare.poolId.datatokenReserve) ? new Decimal(row.poolShare.poolId.datatokenReserve)
.mul(new Decimal(row.poolShare.poolId.consumePrice)) .mul(new Decimal(row.poolShare.poolId.spotPrice))
.plus(row.poolShare.poolId.oceanReserve) .plus(row.poolShare.poolId.oceanReserve)
.toString() .toString()
: '0' : '0'
@ -148,6 +148,7 @@ async function getPoolSharesAssets(
didList.push(did) didList.push(did)
} }
const ddoList = await retrieveDDOListByDIDs(didList, chainIds, cancelToken) const ddoList = await retrieveDDOListByDIDs(didList, chainIds, cancelToken)
for (let i = 0; i < data.length; i++) { for (let i = 0; i < data.length; i++) {
const userLiquidity = calculateUserLiquidity(data[i]) const userLiquidity = calculateUserLiquidity(data[i])
assetList.push({ assetList.push({
@ -176,9 +177,11 @@ export default function PoolShares({
const isMounted = useIsMounted() const isMounted = useIsMounted()
const fetchPoolSharesAssets = useCallback( const fetchPoolSharesAssets = useCallback(
async (cancelToken: CancelToken) => { async (
if (!poolShares || isPoolSharesLoading || !isMounted()) return chainIds: number[],
poolShares: PoolShare[],
cancelToken: CancelToken
) => {
try { try {
const assets = await getPoolSharesAssets( const assets = await getPoolSharesAssets(
poolShares, poolShares,
@ -192,18 +195,23 @@ export default function PoolShares({
setLoading(false) setLoading(false)
} }
}, },
[poolShares, isPoolSharesLoading, isMounted] []
) )
// do not add chainIds,dataFetchInterval to effect dep
useEffect(() => { useEffect(() => {
const cancelToken = newCancelToken() const cancelToken = newCancelToken()
async function init() { async function init() {
setLoading(true) setLoading(true)
await fetchPoolSharesAssets(cancelToken)
if (!poolShares || isPoolSharesLoading || !chainIds || !isMounted())
return
await fetchPoolSharesAssets(chainIds, poolShares, cancelToken)
setLoading(false)
if (dataFetchInterval) return if (dataFetchInterval) return
const interval = setInterval(async () => { const interval = setInterval(async () => {
await fetchPoolSharesAssets(cancelToken) await fetchPoolSharesAssets(chainIds, poolShares, cancelToken)
}, REFETCH_INTERVAL) }, REFETCH_INTERVAL)
setDataFetchInterval(interval) setDataFetchInterval(interval)
} }
@ -212,7 +220,13 @@ export default function PoolShares({
return () => { return () => {
clearInterval(dataFetchInterval) clearInterval(dataFetchInterval)
} }
}, [dataFetchInterval, fetchPoolSharesAssets, newCancelToken]) }, [
fetchPoolSharesAssets,
isPoolSharesLoading,
newCancelToken,
poolShares,
isMounted
])
return accountId ? ( return accountId ? (
<Table <Table

View File

@ -1,5 +1,5 @@
import { Logger } from '@oceanprotocol/lib' import { Logger } from '@oceanprotocol/lib'
import React, { ReactElement, useEffect, useState } from 'react' import React, { ReactElement, useCallback, useEffect, useState } from 'react'
import AssetList from '../../../organisms/AssetList' import AssetList from '../../../organisms/AssetList'
import { getPublishedAssets } from '../../../../utils/aquarius' import { getPublishedAssets } from '../../../../utils/aquarius'
import Filters from '../../../templates/Search/Filters' import Filters from '../../../templates/Search/Filters'
@ -7,6 +7,7 @@ import { useSiteMetadata } from '../../../../hooks/useSiteMetadata'
import { useUserPreferences } from '../../../../providers/UserPreferences' import { useUserPreferences } from '../../../../providers/UserPreferences'
import styles from './PublishedList.module.css' import styles from './PublishedList.module.css'
import { useCancelToken } from '../../../../hooks/useCancelToken' import { useCancelToken } from '../../../../hooks/useCancelToken'
import { PagedAssets } from '../../../../models/PagedAssets'
export default function PublishedList({ export default function PublishedList({
accountId accountId
@ -16,50 +17,53 @@ export default function PublishedList({
const { appConfig } = useSiteMetadata() const { appConfig } = useSiteMetadata()
const { chainIds } = useUserPreferences() const { chainIds } = useUserPreferences()
const [queryResult, setQueryResult] = useState<any>() const [queryResult, setQueryResult] = useState<PagedAssets>()
const [isLoading, setIsLoading] = useState(false) const [isLoading, setIsLoading] = useState(false)
const [page, setPage] = useState<number>(1) const [page, setPage] = useState<number>(1)
const [service, setServiceType] = useState('dataset OR algorithm') const [service, setServiceType] = useState()
const [access, setAccsesType] = useState('access OR compute') const [access, setAccsesType] = useState()
const newCancelToken = useCancelToken() const newCancelToken = useCancelToken()
async function getPublished() { const getPublished = useCallback(
try { async (accountId, chainIds, page, service, access, cancelToken) => {
setIsLoading(true) try {
const result = await getPublishedAssets( setIsLoading(true)
accountId, const result = await getPublishedAssets(
chainIds, accountId.toLowerCase(),
newCancelToken(), chainIds,
page, cancelToken,
service, page,
access service,
) access
setQueryResult(result) )
} catch (error) { setQueryResult(result)
Logger.error(error.message) } catch (error) {
} finally { Logger.error(error.message)
setIsLoading(false) } finally {
} setIsLoading(false)
} }
},
[]
)
useEffect(() => { useEffect(() => {
async function fetchPublishedAssets() { if (queryResult && queryResult.totalPages < page) setPage(1)
await getPublished() }, [page, queryResult])
}
if (page !== 1) {
setPage(1)
} else {
fetchPublishedAssets()
}
}, [service, access])
useEffect(() => { useEffect(() => {
if (!accountId) return if (!accountId) return
async function fetchPublishedAssets() {
await getPublished() getPublished(accountId, chainIds, page, service, access, newCancelToken())
} }, [
fetchPublishedAssets() accountId,
}, [accountId, page, appConfig.metadataCacheUri, chainIds, newCancelToken]) page,
appConfig.metadataCacheUri,
chainIds,
newCancelToken,
getPublished,
service,
access
])
return accountId ? ( return accountId ? (
<> <>

View File

@ -1,13 +1,13 @@
import React, { ReactElement, useState } from 'react' import React, { ReactElement, useState } from 'react'
import { useNavigate } from '@reach/router' import { useNavigate } from '@reach/router'
import classNames from 'classnames/bind' import classNames from 'classnames/bind'
import { import { addExistingParamsToUrl } from './utils'
addExistingParamsToUrl,
FilterByAccessOptions,
FilterByTypeOptions
} from './utils'
import Button from '../../atoms/Button' import Button from '../../atoms/Button'
import styles from './Filters.module.css' import styles from './Filters.module.css'
import {
FilterByAccessOptions,
FilterByTypeOptions
} from '../../../models/SortAndFilters'
const cx = classNames.bind(styles) const cx = classNames.bind(styles)

View File

@ -1,4 +1,4 @@
import React, { ReactElement, useState, useEffect } from 'react' import React, { ReactElement, useState, useEffect, useCallback } from 'react'
import Permission from '../../organisms/Permission' import Permission from '../../organisms/Permission'
import AssetList from '../../organisms/AssetList' import AssetList from '../../organisms/AssetList'
import queryString from 'query-string' import queryString from 'query-string'
@ -10,6 +10,7 @@ import { updateQueryStringParameter } from '../../../utils'
import { useUserPreferences } from '../../../providers/UserPreferences' import { useUserPreferences } from '../../../providers/UserPreferences'
import { useCancelToken } from '../../../hooks/useCancelToken' import { useCancelToken } from '../../../hooks/useCancelToken'
import styles from './index.module.css' import styles from './index.module.css'
import { PagedAssets } from '../../../models/PagedAssets'
export default function SearchPage({ export default function SearchPage({
location, location,
@ -20,54 +21,61 @@ export default function SearchPage({
setTotalResults: (totalResults: number) => void setTotalResults: (totalResults: number) => void
setTotalPagesNumber: (totalPagesNumber: number) => void setTotalPagesNumber: (totalPagesNumber: number) => void
}): ReactElement { }): ReactElement {
const parsed = queryString.parse(location.search) const [parsed, setParsed] = useState<queryString.ParsedQuery<string>>()
const { text, owner, tags, page, sort, sortOrder, serviceType, accessType } =
parsed
const { chainIds } = useUserPreferences() const { chainIds } = useUserPreferences()
const [queryResult, setQueryResult] = useState<any>() const [queryResult, setQueryResult] = useState<PagedAssets>()
const [loading, setLoading] = useState<boolean>() const [loading, setLoading] = useState<boolean>()
const [service, setServiceType] = useState<string>(serviceType as string) const [serviceType, setServiceType] = useState<string>()
const [access, setAccessType] = useState<string>(accessType as string) const [accessType, setAccessType] = useState<string>()
const [sortType, setSortType] = useState<string>(sort as string) const [sortType, setSortType] = useState<string>()
const [sortDirection, setSortDirection] = useState<string>( const [sortDirection, setSortDirection] = useState<string>()
sortOrder as string
)
const newCancelToken = useCancelToken() const newCancelToken = useCancelToken()
async function fetchAssets() { useEffect(() => {
setLoading(true) const parsed = queryString.parse(location.search)
setTotalResults(undefined) const { sort, sortOrder, serviceType, accessType } = parsed
const queryResult = await getResults(parsed, chainIds, newCancelToken()) setParsed(parsed)
setServiceType(serviceType as string)
setAccessType(accessType as string)
setSortDirection(sortOrder as string)
setSortType(sort as string)
}, [location])
setQueryResult(queryResult) const updatePage = useCallback(
setTotalResults(queryResult.totalResults) (page: number) => {
setTotalPagesNumber(queryResult.totalPages) const { pathname, search } = location
setLoading(false) const newUrl = updateQueryStringParameter(
} pathname + search,
'page',
`${page}`
)
return navigate(newUrl)
},
[location]
)
function setPage(page: number) { const fetchAssets = useCallback(
const newUrl = updateQueryStringParameter( async (parsed: queryString.ParsedQuery<string>, chainIds: number[]) => {
location.pathname + location.search, setLoading(true)
'page', setTotalResults(undefined)
`${page}` const queryResult = await getResults(parsed, chainIds, newCancelToken())
) setQueryResult(queryResult)
return navigate(newUrl) setTotalResults(queryResult.totalResults)
} setTotalPagesNumber(queryResult.totalPages)
setLoading(false)
},
[newCancelToken, setTotalPagesNumber, setTotalResults]
)
useEffect(() => {
if (!parsed || !queryResult) return
const { page } = parsed
if (queryResult.totalPages < Number(page)) updatePage(1)
}, [parsed, queryResult, updatePage])
useEffect(() => { useEffect(() => {
async function initSearch() { if (!parsed || !chainIds) return
await fetchAssets() fetchAssets(parsed, chainIds)
} }, [parsed, chainIds, newCancelToken, fetchAssets])
initSearch()
}, [text, owner, tags, sort, page, sortOrder, chainIds, newCancelToken])
useEffect(() => {
if (page !== '1') {
setPage(1)
} else {
fetchAssets()
}
}, [serviceType, accessType])
return ( return (
<Permission eventType="browse"> <Permission eventType="browse">
@ -75,8 +83,8 @@ export default function SearchPage({
<div className={styles.search}> <div className={styles.search}>
<div className={styles.row}> <div className={styles.row}>
<Filters <Filters
serviceType={service} serviceType={serviceType}
accessType={access} accessType={accessType}
setServiceType={setServiceType} setServiceType={setServiceType}
setAccessType={setAccessType} setAccessType={setAccessType}
addFiltersToUrl addFiltersToUrl
@ -96,7 +104,7 @@ export default function SearchPage({
isLoading={loading} isLoading={loading}
page={queryResult?.page} page={queryResult?.page}
totalPages={queryResult?.totalPages} totalPages={queryResult?.totalPages}
onPageChange={setPage} onPageChange={updatePage}
/> />
</div> </div>
</> </>

View File

@ -1,13 +1,13 @@
import React, { ReactElement } from 'react' import React, { ReactElement } from 'react'
import { useNavigate } from '@reach/router' import { useNavigate } from '@reach/router'
import { import { addExistingParamsToUrl } from './utils'
addExistingParamsToUrl,
SortTermOptions,
SortValueOptions
} from './utils'
import Button from '../../atoms/Button' import Button from '../../atoms/Button'
import styles from './sort.module.css' import styles from './sort.module.css'
import classNames from 'classnames/bind' import classNames from 'classnames/bind'
import {
SortDirectionOptions,
SortTermOptions
} from '../../../models/SortAndFilters'
const cx = classNames.bind(styles) const cx = classNames.bind(styles)
@ -29,7 +29,7 @@ export default function Sort({
}): ReactElement { }): ReactElement {
const navigate = useNavigate() const navigate = useNavigate()
const directionArrow = String.fromCharCode( const directionArrow = String.fromCharCode(
sortDirection === SortValueOptions.Ascending ? 9650 : 9660 sortDirection === SortDirectionOptions.Ascending ? 9650 : 9660
) )
async function sortResults(sortBy?: string, direction?: string) { async function sortResults(sortBy?: string, direction?: string) {
let urlLocation: string let urlLocation: string
@ -46,10 +46,10 @@ export default function Sort({
} }
function handleSortButtonClick(value: string) { function handleSortButtonClick(value: string) {
if (value === sortType) { if (value === sortType) {
if (sortDirection === SortValueOptions.Descending) { if (sortDirection === SortDirectionOptions.Descending) {
sortResults(null, SortValueOptions.Ascending) sortResults(null, SortDirectionOptions.Ascending)
} else { } else {
sortResults(null, SortValueOptions.Descending) sortResults(null, SortDirectionOptions.Descending)
} }
} else { } else {
sortResults(value, null) sortResults(value, null)

View File

@ -1,51 +1,18 @@
import { Logger } from '@oceanprotocol/lib' import { Logger } from '@oceanprotocol/lib'
import { import {
queryMetadata, generateBaseQuery,
transformChainIdsListToQuery getFilterTerm,
queryMetadata
} from '../../../utils/aquarius' } from '../../../utils/aquarius'
import queryString from 'query-string' import queryString from 'query-string'
import { CancelToken } from 'axios' import { CancelToken } from 'axios'
import { BaseQueryParams } from '../../../models/aquarius/BaseQueryParams'
export const SortTermOptions = { import { SearchQuery } from '../../../models/aquarius/SearchQuery'
Created: 'created', import { FilterTerm } from '../../../models/aquarius/FilterTerm'
Relevance: '_score' import {
} as const SortDirectionOptions,
type SortTermOptions = typeof SortTermOptions[keyof typeof SortTermOptions] SortTermOptions
} from '../../../models/SortAndFilters'
export const SortElasticTerm = {
Liquidity: 'price.ocean',
Price: 'price.value',
Created: 'created'
} as const
type SortElasticTerm = typeof SortElasticTerm[keyof typeof SortElasticTerm]
export const SortValueOptions = {
Ascending: 'asc',
Descending: 'desc'
} as const
type SortValueOptions = typeof SortValueOptions[keyof typeof SortValueOptions]
export const FilterByTypeOptions = {
Data: 'dataset',
Algorithm: 'algorithm'
} as const
type FilterByTypeOptions =
typeof FilterByTypeOptions[keyof typeof FilterByTypeOptions]
export const FilterByAccessOptions = {
Download: 'access',
Compute: 'compute'
}
type FilterByAccessOptions =
typeof FilterByAccessOptions[keyof typeof FilterByAccessOptions]
function getSortType(sortParam: string): string {
const sortTerm =
sortParam === SortTermOptions.Created
? SortTermOptions.Created
: SortTermOptions.Relevance
return sortTerm
}
export function escapeESReservedChars(text: string): string { export function escapeESReservedChars(text: string): string {
return text?.replace(/([!*+\-=<>&|()\\[\]{}^~?:\\/"])/g, '\\$1') return text?.replace(/([!*+\-=<>&|()\\[\]{}^~?:\\/"])/g, '\\$1')
@ -60,10 +27,10 @@ export function getSearchQuery(
page?: string, page?: string,
offset?: string, offset?: string,
sort?: string, sort?: string,
sortOrder?: string, sortDirection?: string,
serviceType?: string, serviceType?: string,
accessType?: string accessType?: string
): any { ): SearchQuery {
text = escapeESReservedChars(text) text = escapeESReservedChars(text)
const emptySearchTerm = text === undefined || text === '' const emptySearchTerm = text === undefined || text === ''
@ -98,81 +65,70 @@ export function getSearchQuery(
'service.attributes.additionalInformation.description', 'service.attributes.additionalInformation.description',
'service.attributes.additionalInformation.tags' 'service.attributes.additionalInformation.tags'
] ]
return {
from: (Number(page) - 1 || 0) * (Number(offset) || 21), const nestedQuery = {
size: Number(offset) || 21, must: [
query: { {
bool: { bool: {
must: [ should: [
{ {
bool: { query_string: {
should: [ query: `${modifiedSearchTerm}`,
{ fields: searchFields,
query_string: { minimum_should_match: '2<75%',
query: `${modifiedSearchTerm}`, phrase_slop: 2,
fields: searchFields, boost: 5
minimum_should_match: '2<75%', }
phrase_slop: 2, },
boost: 5 {
} query_string: {
}, query: `${noSpaceSearchTerm}*`,
{ fields: searchFields,
query_string: { boost: 5,
query: `${noSpaceSearchTerm}*`, lenient: true
fields: searchFields, }
boost: 5, },
lenient: true {
} match_phrase: {
}, content: {
{ query: `${searchTerm}`,
match_phrase: { boost: 10
content: {
query: `${searchTerm}`,
boost: 10
}
}
},
{
query_string: {
query: `${prefixedSearchTerm}`,
fields: searchFields,
default_operator: 'AND'
}
} }
] }
},
{
query_string: {
query: `${prefixedSearchTerm}`,
fields: searchFields,
default_operator: 'AND'
}
} }
}, ]
{ }
match: {
'service.attributes.main.type':
serviceType === undefined
? 'dataset OR algorithm'
: `${serviceType}`
}
},
{
match: {
'service.type':
accessType === undefined ? 'access OR compute' : `${accessType}`
}
},
{
query_string: {
query: `${transformChainIdsListToQuery(chainIds)}`
}
},
{
term: {
isInPurgatory: false
}
}
]
} }
}, ]
sort: {
[sort]: sortOrder
}
} }
const filters: FilterTerm[] = []
accessType !== undefined &&
filters.push(getFilterTerm('service.type', accessType))
serviceType !== undefined &&
filters.push(getFilterTerm('service.attributes.main.type', serviceType))
const baseQueryParams = {
chainIds,
nestedQuery,
esPaginationOptions: {
from: (Number(page) - 1 || 0) * (Number(offset) || 21),
size: Number(offset) || 21
},
sortOptions: { sortBy: sort, sortDirection: sortDirection },
filters
} as BaseQueryParams
const query = generateBaseQuery(baseQueryParams)
return query
} }
export async function getResults( export async function getResults(
@ -242,7 +198,7 @@ export async function addExistingParamsToUrl(
// sort should be relevance when fixed in aqua // sort should be relevance when fixed in aqua
urlLocation = `${urlLocation}sort=${encodeURIComponent( urlLocation = `${urlLocation}sort=${encodeURIComponent(
SortTermOptions.Relevance SortTermOptions.Relevance
)}&sortOrder=${SortValueOptions.Descending}&` )}&sortOrder=${SortDirectionOptions.Descending}&`
} }
urlLocation = urlLocation.slice(0, -1) urlLocation = urlLocation.slice(0, -1)
return urlLocation return urlLocation

View File

@ -0,0 +1,8 @@
import { DDO } from '@oceanprotocol/lib'
export interface PagedAssets {
results: DDO[]
page: number
totalPages: number
totalResults: number
}

View File

@ -0,0 +1,26 @@
export enum SortDirectionOptions {
Ascending = 'asc',
Descending = 'desc'
}
export enum SortTermOptions {
Created = 'created',
Relevance = '_score'
}
export enum FilterByTypeOptions {
Data = 'dataset',
Algorithm = 'algorithm'
}
export enum FilterByAccessOptions {
Download = 'access',
Compute = 'compute'
}
export interface SortOptions {
sortBy: SortTermOptions
sortDirection?: SortDirectionOptions
}
export type Filters = FilterByTypeOptions | FilterByAccessOptions

View File

@ -0,0 +1,12 @@
import { SortOptions } from '../SortAndFilters'
import { EsPaginationOptions } from './EsPaginationOptions'
import { FilterTerm } from './FilterTerm'
export interface BaseQueryParams {
chainIds: number[]
nestedQuery?: any
esPaginationOptions?: EsPaginationOptions
sortOptions?: SortOptions
filters?: FilterTerm[]
ignorePurgatory?: boolean
}

View File

@ -0,0 +1,8 @@
import { DDO } from '@oceanprotocol/lib'
export interface DownloadedAsset {
dtSymbol: string
timestamp: number
networkId: number
ddo: DDO
}

View File

@ -0,0 +1,4 @@
export interface EsPaginationOptions {
from?: number
size?: number
}

View File

@ -0,0 +1,5 @@
export interface FilterTerm {
[property: string]: {
[property: string]: string | number | boolean | number[] | string[]
}
}

View File

@ -0,0 +1,8 @@
import { SortDirectionOptions } from '../SortAndFilters'
export interface SearchQuery {
from?: number
size?: number
// eslint-disable-next-line @typescript-eslint/no-explicit-any
query: any
sort?: { [jsonPath: string]: SortDirectionOptions }
}

View File

@ -0,0 +1,41 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable camelcase */
import { DDO } from '@oceanprotocol/lib'
export interface Explanation {
value: number
description: string
details: Explanation[]
}
export interface ShardsResponse {
total: number
successful: number
failed: number
skipped: number
}
export interface SearchResponse {
took: number
timed_out: boolean
_scroll_id?: string | undefined
_shards: ShardsResponse
hits: {
total: number
max_score: number
hits: Array<{
_index: string
_type: string
_id: string
_score: number
_source: DDO
_version?: number | undefined
_explanation?: Explanation | undefined
fields?: any
highlight?: any
inner_hits?: any
matched_queries?: string[] | undefined
sort?: string[] | undefined
}>
}
aggregations?: any
}

View File

@ -52,8 +52,8 @@ export default function PageGatsbySearch(props: PageProps): ReactElement {
> >
<PageSearch <PageSearch
location={props.location} location={props.location}
setTotalResults={(totalResults) => setTotalResults(totalResults)} setTotalResults={setTotalResults}
setTotalPagesNumber={(totalPages) => setTotalPagesNumber(totalPages)} setTotalPagesNumber={setTotalPagesNumber}
/> />
</Page> </Page>
) )

View File

@ -15,11 +15,7 @@ import {
import { useUserPreferences } from './UserPreferences' import { useUserPreferences } from './UserPreferences'
import { PoolShares_poolShares as PoolShare } from '../@types/apollo/PoolShares' import { PoolShares_poolShares as PoolShare } from '../@types/apollo/PoolShares'
import { DDO, Logger } from '@oceanprotocol/lib' import { DDO, Logger } from '@oceanprotocol/lib'
import { import { getDownloadAssets, getPublishedAssets } from '../utils/aquarius'
DownloadedAsset,
getDownloadAssets,
getPublishedAssets
} from '../utils/aquarius'
import { useSiteMetadata } from '../hooks/useSiteMetadata' import { useSiteMetadata } from '../hooks/useSiteMetadata'
import { Profile } from '../models/Profile' import { Profile } from '../models/Profile'
import { accountTruncate } from '../utils/web3' import { accountTruncate } from '../utils/web3'
@ -27,6 +23,7 @@ import axios, { CancelToken } from 'axios'
import ethereumAddress from 'ethereum-address' import ethereumAddress from 'ethereum-address'
import get3BoxProfile from '../utils/profile' import get3BoxProfile from '../utils/profile'
import web3 from 'web3' import web3 from 'web3'
import { DownloadedAsset } from '../models/aquarius/DownloadedAsset'
interface ProfileProviderValue { interface ProfileProviderValue {
profile: Profile profile: Profile
@ -134,31 +131,34 @@ function ProfileProvider({
const [isPoolSharesLoading, setIsPoolSharesLoading] = useState<boolean>(false) const [isPoolSharesLoading, setIsPoolSharesLoading] = useState<boolean>(false)
const [poolSharesInterval, setPoolSharesInterval] = useState<NodeJS.Timeout>() const [poolSharesInterval, setPoolSharesInterval] = useState<NodeJS.Timeout>()
const fetchPoolShares = useCallback(async () => { const fetchPoolShares = useCallback(
if (!accountId || !chainIds || !isEthAddress) return async (accountId, chainIds, isEthAddress) => {
if (!accountId || !chainIds || !isEthAddress) return
try { try {
setIsPoolSharesLoading(true) setIsPoolSharesLoading(true)
const poolShares = await getPoolSharesData(accountId, chainIds) const poolShares = await getPoolSharesData(accountId, chainIds)
setPoolShares(poolShares) setPoolShares(poolShares)
Logger.log( Logger.log(
`[profile] Fetched ${poolShares.length} pool shares.`, `[profile] Fetched ${poolShares.length} pool shares.`,
poolShares poolShares
) )
} catch (error) { } catch (error) {
Logger.error('Error fetching pool shares: ', error.message) Logger.error('Error fetching pool shares: ', error.message)
} finally { } finally {
setIsPoolSharesLoading(false) setIsPoolSharesLoading(false)
} }
}, [accountId, chainIds, isEthAddress]) },
[]
)
useEffect(() => { useEffect(() => {
async function init() { async function init() {
await fetchPoolShares() await fetchPoolShares(accountId, chainIds, isEthAddress)
if (poolSharesInterval) return if (poolSharesInterval) return
const interval = setInterval(async () => { const interval = setInterval(async () => {
await fetchPoolShares() await fetchPoolShares(accountId, chainIds, isEthAddress)
}, refreshInterval) }, refreshInterval)
setPoolSharesInterval(interval) setPoolSharesInterval(interval)
} }
@ -167,7 +167,7 @@ function ProfileProvider({
return () => { return () => {
clearInterval(poolSharesInterval) clearInterval(poolSharesInterval)
} }
}, [poolSharesInterval, fetchPoolShares]) }, [poolSharesInterval, fetchPoolShares, accountId, chainIds, isEthAddress])
// //
// PUBLISHED ASSETS // PUBLISHED ASSETS

View File

@ -10,49 +10,70 @@ import { PriceList, getAssetsPriceList } from './subgraph'
import axios, { CancelToken, AxiosResponse } from 'axios' import axios, { CancelToken, AxiosResponse } from 'axios'
import { OrdersData_tokenOrders as OrdersData } from '../@types/apollo/OrdersData' import { OrdersData_tokenOrders as OrdersData } from '../@types/apollo/OrdersData'
import { metadataCacheUri } from '../../app.config' import { metadataCacheUri } from '../../app.config'
import { DownloadedAsset } from '../models/aquarius/DownloadedAsset'
export interface DownloadedAsset { import { SearchQuery } from '../models/aquarius/SearchQuery'
dtSymbol: string import { SearchResponse } from '../models/aquarius/SearchResponse'
timestamp: number import { PagedAssets } from '../models/PagedAssets'
networkId: number import { SortDirectionOptions, SortTermOptions } from '../models/SortAndFilters'
ddo: DDO import { FilterTerm } from '../models/aquarius/FilterTerm'
} import { BaseQueryParams } from '../models/aquarius/BaseQueryParams'
export const MAXIMUM_NUMBER_OF_PAGES_WITH_RESULTS = 476 export const MAXIMUM_NUMBER_OF_PAGES_WITH_RESULTS = 476
function getQueryForAlgorithmDatasets(algorithmDid: string, chainId?: number) { /**
* @param filterField the name of the actual field from the ddo schema e.g. 'id','service.attributes.main.type'
* @param value the value of the filter
* @returns json structure of the es filter
*/
export function getFilterTerm(
filterField: string,
value: string | number | boolean | number[] | string[]
): FilterTerm {
const isArray = Array.isArray(value)
return { return {
query: { [isArray ? 'terms' : 'term']: {
bool: { [filterField]: value
must: [ }
{
match: {
'service.attributes.main.privacy.publisherTrustedAlgorithms.did':
algorithmDid
}
},
{
query_string: {
query: `chainId:${chainId}`
}
}
]
}
},
sort: { created: 'desc' }
} }
} }
// TODO: import directly from ocean.js somehow. export function generateBaseQuery(
// Transforming Aquarius' direct response is needed for getting actual DDOs baseQueryParams: BaseQueryParams
// and not just strings of DDOs. For now, taken from ): SearchQuery {
// https://github.com/oceanprotocol/ocean.js/blob/main/src/metadatacache/MetadataCache.ts#L361-L375 const generatedQuery = {
from: baseQueryParams.esPaginationOptions?.from || 0,
size: baseQueryParams.esPaginationOptions?.size || 1000,
query: {
bool: {
...baseQueryParams.nestedQuery,
filter: [
...(baseQueryParams.filters || []),
getFilterTerm('chainId', baseQueryParams.chainIds),
getFilterTerm('_index', 'aquarius'),
...(baseQueryParams.ignorePurgatory
? []
: [getFilterTerm('isInPurgatory', 'false')])
]
}
}
} as SearchQuery
if (baseQueryParams.sortOptions !== undefined)
generatedQuery.sort = {
[baseQueryParams.sortOptions.sortBy]:
baseQueryParams.sortOptions.sortDirection ||
SortDirectionOptions.Descending
}
return generatedQuery
}
export function transformQueryResult( export function transformQueryResult(
queryResult: any, queryResult: SearchResponse,
from = 0, from = 0,
size = 21 size = 21
): any { ): PagedAssets {
const result: any = { const result: PagedAssets = {
results: [], results: [],
page: 0, page: 0,
totalPages: 0, totalPages: 0,
@ -60,7 +81,7 @@ export function transformQueryResult(
} }
result.results = (queryResult.hits.hits || []).map( result.results = (queryResult.hits.hits || []).map(
(hit: any) => new DDO(hit._source as DDO) (hit) => new DDO(hit._source as DDO)
) )
result.totalResults = queryResult.hits.total result.totalResults = queryResult.hits.total
result.totalPages = result.totalPages =
@ -72,31 +93,12 @@ export function transformQueryResult(
return result return result
} }
export function transformChainIdsListToQuery(chainIds: number[]): string {
let chainQuery = ''
chainIds.forEach((chainId) => {
chainQuery += `chainId:${chainId} OR `
})
chainQuery = chainQuery.slice(0, chainQuery.length - 4)
return chainQuery
}
export function transformDIDListToQuery(didList: string[] | DID[]): string {
let chainQuery = ''
const regex = new RegExp('(:)', 'g')
didList.forEach((did: any) => {
chainQuery += `id:${did.replace(regex, '\\:')} OR `
})
chainQuery = chainQuery.slice(0, chainQuery.length - 4)
return chainQuery
}
export async function queryMetadata( export async function queryMetadata(
query: any, query: SearchQuery,
cancelToken: CancelToken cancelToken: CancelToken
): Promise<any> { ): Promise<PagedAssets> {
try { try {
const response: AxiosResponse<any> = await axios.post( const response: AxiosResponse<SearchResponse> = await axios.post(
`${metadataCacheUri}/api/v1/aquarius/assets/query`, `${metadataCacheUri}/api/v1/aquarius/assets/query`,
{ ...query }, { ...query },
{ cancelToken } { cancelToken }
@ -155,6 +157,53 @@ export async function getAssetsNames(
} }
} }
export async function getAssetsFromDidList(
didList: string[],
chainIds: number[],
cancelToken: CancelToken
): Promise<any> {
try {
if (!(didList.length > 0)) return
const baseParams = {
chainIds: chainIds,
filters: [getFilterTerm('id', didList)],
ignorePurgatory: true
} as BaseQueryParams
const query = generateBaseQuery(baseParams)
const queryResult = await queryMetadata(query, cancelToken)
return queryResult
} catch (error) {
Logger.error(error.message)
}
}
export async function retrieveDDOListByDIDs(
didList: string[],
chainIds: number[],
cancelToken: CancelToken
): Promise<DDO[]> {
try {
if (didList?.length === 0 || chainIds?.length === 0) return []
const orderedDDOListByDIDList: DDO[] = []
const baseQueryparams = {
chainIds,
filters: [getFilterTerm('id', didList)],
ignorePurgatory: true
} as BaseQueryParams
const query = generateBaseQuery(baseQueryparams)
const result = await queryMetadata(query, cancelToken)
didList.forEach((did: string | DID) => {
const ddo: DDO = result.results.find((ddo: DDO) => ddo.id === did)
orderedDDOListByDIDList.push(ddo)
})
return orderedDDOListByDIDList
} catch (error) {
Logger.error(error.message)
}
}
export async function transformDDOToAssetSelection( export async function transformDDOToAssetSelection(
datasetProviderEndpoint: string, datasetProviderEndpoint: string,
ddoList: DDO[], ddoList: DDO[],
@ -212,60 +261,34 @@ export async function getAlgorithmDatasetsForCompute(
datasetChainId?: number, datasetChainId?: number,
cancelToken?: CancelToken cancelToken?: CancelToken
): Promise<AssetSelectionAsset[]> { ): Promise<AssetSelectionAsset[]> {
const computeDatasets = await queryMetadata( const baseQueryParams = {
getQueryForAlgorithmDatasets(algorithmId, datasetChainId), chainIds: [datasetChainId],
cancelToken filters: [
) getFilterTerm(
const computeDatasetsForCurrentAlgorithm: DDO[] = [] 'service.attributes.main.privacy.publisherTrustedAlgorithms.did',
computeDatasets.results.forEach((data: DDO) => { algorithmId
const algorithm = data
.findServiceByType('compute')
.attributes.main.privacy.publisherTrustedAlgorithms.find(
(algo) => algo.did === algorithmId
) )
algorithm && computeDatasetsForCurrentAlgorithm.push(data) ],
}) sortOptions: {
if (computeDatasetsForCurrentAlgorithm.length === 0) { sortBy: SortTermOptions.Created,
return [] sortDirection: SortDirectionOptions.Descending
} }
} as BaseQueryParams
const query = generateBaseQuery(baseQueryParams)
const computeDatasets = await queryMetadata(query, cancelToken)
if (computeDatasets.totalResults === 0) return []
const datasets = await transformDDOToAssetSelection( const datasets = await transformDDOToAssetSelection(
datasetProviderUri, datasetProviderUri,
computeDatasetsForCurrentAlgorithm, computeDatasets.results,
[], [],
cancelToken cancelToken
) )
return datasets return datasets
} }
export async function retrieveDDOListByDIDs(
didList: string[] | DID[],
chainIds: number[],
cancelToken: CancelToken
): Promise<DDO[]> {
try {
if (didList?.length === 0 || chainIds?.length === 0) return []
const orderedDDOListByDIDList: DDO[] = []
const query = {
size: didList.length,
query: {
query_string: {
query: `(${transformDIDListToQuery(
didList
)}) AND (${transformChainIdsListToQuery(chainIds)})`
}
}
}
const result = await queryMetadata(query, cancelToken)
didList.forEach((did: string | DID) => {
const ddo: DDO = result.results.find((ddo: DDO) => ddo.id === did)
orderedDDOListByDIDList.push(ddo)
})
return orderedDDOListByDIDList
} catch (error) {
Logger.error(error.message)
}
}
export async function getPublishedAssets( export async function getPublishedAssets(
accountId: string, accountId: string,
chainIds: number[], chainIds: number[],
@ -273,26 +296,33 @@ export async function getPublishedAssets(
page?: number, page?: number,
type?: string, type?: string,
accesType?: string accesType?: string
): Promise<any> { ): Promise<PagedAssets> {
if (!accountId) return if (!accountId) return
type = type || 'dataset OR algorithm' const filters: FilterTerm[] = []
accesType = accesType || 'access OR compute'
const queryPublishedAssets = { filters.push(getFilterTerm('publicKey.owner', accountId.toLowerCase()))
from: (Number(page) - 1 || 0) * (Number(9) || 21), accesType !== undefined &&
size: Number(9) || 21, filters.push(getFilterTerm('service.type', accesType))
query: { type !== undefined &&
query_string: { filters.push(getFilterTerm('service.attributes.main.type', type))
query: `(publicKey.owner:${accountId}) AND (service.attributes.main.type:${type}) AND (service.type:${accesType}) AND (${transformChainIdsListToQuery(
chainIds const baseQueryParams = {
)})` chainIds,
} filters,
sortOptions: {
sortBy: SortTermOptions.Created,
sortDirection: SortDirectionOptions.Descending
}, },
sort: { created: 'desc' } esPaginationOptions: {
} from: (Number(page) - 1 || 0) * 9,
size: 9
}
} as BaseQueryParams
const query = generateBaseQuery(baseQueryParams)
try { try {
const result = await queryMetadata(queryPublishedAssets, cancelToken) const result = await queryMetadata(query, cancelToken)
return result return result
} catch (error) { } catch (error) {
if (axios.isCancel(error)) { if (axios.isCancel(error)) {
@ -309,38 +339,34 @@ export async function getDownloadAssets(
chainIds: number[], chainIds: number[],
cancelToken: CancelToken cancelToken: CancelToken
): Promise<DownloadedAsset[]> { ): Promise<DownloadedAsset[]> {
const downloadedAssets: DownloadedAsset[] = []
try { try {
const queryResult = await retrieveDDOListByDIDs( const baseQueryparams = {
didList,
chainIds, chainIds,
cancelToken filters: [
) getFilterTerm('id', didList),
const ddoList = queryResult getFilterTerm('service.type', 'access')
]
} as BaseQueryParams
const query = generateBaseQuery(baseQueryparams)
const result = await queryMetadata(query, cancelToken)
for (let i = 0; i < tokenOrders?.length; i++) { const downloadedAssets: DownloadedAsset[] = result.results
const ddo = ddoList.filter( .map((ddo) => {
(ddo: { dataToken: string }) => const order = tokenOrders.find(
tokenOrders[i].datatokenId.address.toLowerCase() === ({ datatokenId }) =>
ddo.dataToken.toLowerCase() datatokenId?.address.toLowerCase() === ddo.dataToken.toLowerCase()
)[0] )
// make sure we are only pushing download orders return {
if (ddo.service[1].type !== 'access') continue ddo,
networkId: ddo.chainId,
downloadedAssets.push({ dtSymbol: order?.datatokenId?.symbol,
ddo, timestamp: order?.timestamp
networkId: ddo.chainId, }
dtSymbol: tokenOrders[i].datatokenId.symbol,
timestamp: tokenOrders[i].timestamp
}) })
} .sort((a, b) => b.timestamp - a.timestamp)
const sortedOrders = downloadedAssets.sort( return downloadedAssets
(a, b) => b.timestamp - a.timestamp
)
return sortedOrders
} catch (error) { } catch (error) {
Logger.error(error.message) Logger.error(error.message)
} }

View File

@ -12,12 +12,13 @@ import {
import { ComputePrivacyForm } from '../models/FormEditComputeDataset' import { ComputePrivacyForm } from '../models/FormEditComputeDataset'
import web3 from 'web3' import web3 from 'web3'
import { ComputeJob } from '@oceanprotocol/lib/dist/node/ocean/interfaces/Compute' import { ComputeJob } from '@oceanprotocol/lib/dist/node/ocean/interfaces/Compute'
import axios, { CancelToken } from 'axios' import { CancelToken } from 'axios'
import { gql } from 'urql' import { gql } from 'urql'
import { ComputeJobMetaData } from '../@types/ComputeJobMetaData' import { ComputeJobMetaData } from '../@types/ComputeJobMetaData'
import { transformChainIdsListToQuery, queryMetadata } from './aquarius' import { queryMetadata, getFilterTerm, generateBaseQuery } from './aquarius'
import { fetchDataForMultipleChains } from './subgraph' import { fetchDataForMultipleChains } from './subgraph'
import { OrdersData_tokenOrders_datatokenId as OrdersDatatoken } from '../@types/apollo/OrdersData' import { OrdersData_tokenOrders_datatokenId as OrdersDatatoken } from '../@types/apollo/OrdersData'
import { BaseQueryParams } from '../models/aquarius/BaseQueryParams'
const getComputeOrders = gql` const getComputeOrders = gql`
query ComputeOrders($user: String!) { query ComputeOrders($user: String!) {
@ -72,22 +73,22 @@ interface ComputeResults {
} }
async function getAssetMetadata( async function getAssetMetadata(
queryDtList: string, queryDtList: string[],
cancelToken: CancelToken, cancelToken: CancelToken,
chainIds: number[] chainIds: number[]
): Promise<DDO[]> { ): Promise<DDO[]> {
const queryDid = { const baseQueryparams = {
query: { chainIds,
query_string: { filters: [
query: `(${queryDtList}) AND (${transformChainIdsListToQuery( getFilterTerm('dataToken', queryDtList),
chainIds getFilterTerm('service.type', 'compute'),
)}) AND service.attributes.main.type:dataset AND service.type:compute`, getFilterTerm('service.attributes.main.type', 'dataset')
fields: ['dataToken'] ],
} ignorePurgatory: true
} } as BaseQueryParams
} const query = generateBaseQuery(baseQueryparams)
const result = await queryMetadata(query, cancelToken)
const result = await queryMetadata(queryDid, cancelToken)
return result.results return result.results
} }
@ -206,18 +207,14 @@ async function getJobs(
return computeJobs return computeJobs
} }
function getDtList(data: TokenOrder[]) { function getDtList(data: TokenOrder[]): string[] {
const dtList = [] const dtList = []
for (let i = 0; i < data.length; i++) { for (let i = 0; i < data.length; i++) {
dtList.push(data[i].datatokenId.address) dtList.push(data[i].datatokenId.address)
} }
const queryDtList = JSON.stringify(dtList)
.replace(/,/g, ' ')
.replace(/"/g, '')
.replace(/(\[|\])/g, '')
return queryDtList return dtList
} }
export async function getComputeJobs( export async function getComputeJobs(
@ -225,7 +222,8 @@ export async function getComputeJobs(
config: Config, config: Config,
ocean: Ocean, ocean: Ocean,
account: Account, account: Account,
ddo?: DDO ddo?: DDO,
token?: CancelToken
): Promise<ComputeResults> { ): Promise<ComputeResults> {
const assetDTAddress = ddo?.dataTokenInfo?.address const assetDTAddress = ddo?.dataTokenInfo?.address
let computeResult: ComputeResults = { let computeResult: ComputeResults = {
@ -262,10 +260,9 @@ export async function getComputeJobs(
data = data.sort((a, b) => b.timestamp - a.timestamp) data = data.sort((a, b) => b.timestamp - a.timestamp)
const queryDtList = getDtList(data) const queryDtList = getDtList(data)
if (queryDtList === '') return if (!queryDtList) return
const source = axios.CancelToken.source() const assets = await getAssetMetadata(queryDtList, token, chainIds)
const assets = await getAssetMetadata(queryDtList, source.token, chainIds)
const serviceEndpoints = getServiceEndpoints(data, assets) const serviceEndpoints = getServiceEndpoints(data, assets)
const providers: Provider[] = await getProviders( const providers: Provider[] = await getProviders(
serviceEndpoints, serviceEndpoints,

View File

@ -590,10 +590,10 @@ export async function getAssetsBestPrices(
return assetsWithPrice return assetsWithPrice
} }
export async function getHighestLiquidityDIDs( export async function getHighestLiquidityDatatokens(
chainIds: number[] chainIds: number[]
): Promise<[string, number]> { ): Promise<string[]> {
const didList: string[] = [] const dtList: string[] = []
let highestLiquidityAssets: HighestLiquidityAssetsPool[] = [] let highestLiquidityAssets: HighestLiquidityAssetsPool[] = []
for (const chain of chainIds) { for (const chain of chainIds) {
const queryContext = getQueryContext(Number(chain)) const queryContext = getQueryContext(Number(chain))
@ -603,22 +603,12 @@ export async function getHighestLiquidityDIDs(
fetchedPools.data.pools fetchedPools.data.pools
) )
} }
highestLiquidityAssets highestLiquidityAssets.sort((a, b) => b.oceanReserve - a.oceanReserve)
.sort((a, b) => a.oceanReserve - b.oceanReserve)
.reverse()
for (let i = 0; i < highestLiquidityAssets.length; i++) { for (let i = 0; i < highestLiquidityAssets.length; i++) {
if (!highestLiquidityAssets[i].datatokenAddress) continue if (!highestLiquidityAssets[i].datatokenAddress) continue
const did = web3.utils dtList.push(highestLiquidityAssets[i].datatokenAddress)
.toChecksumAddress(highestLiquidityAssets[i].datatokenAddress)
.replace('0x', 'did:op:')
didList.push(did)
} }
const searchDids = JSON.stringify(didList) return dtList
.replace(/,/g, ' ')
.replace(/"/g, '')
.replace(/(\[|\])/g, '')
.replace(/(did:op:)/g, '0x')
return [searchDids, didList.length]
} }
export function calculateUserLiquidity(poolShare: PoolShare): number { export function calculateUserLiquidity(poolShare: PoolShare): number {
@ -628,7 +618,7 @@ export function calculateUserLiquidity(poolShare: PoolShare): number {
const datatokens = const datatokens =
(poolShare.balance / poolShare.poolId.totalShares) * (poolShare.balance / poolShare.poolId.totalShares) *
poolShare.poolId.datatokenReserve poolShare.poolId.datatokenReserve
const totalLiquidity = ocean + datatokens * poolShare.poolId.consumePrice const totalLiquidity = ocean + datatokens * poolShare.poolId.spotPrice
return totalLiquidity return totalLiquidity
} }
@ -648,6 +638,7 @@ export async function getAccountLiquidityInOwnAssets(
) )
let totalLiquidity = 0 let totalLiquidity = 0
let totalOceanLiquidity = 0 let totalOceanLiquidity = 0
for (const result of results) { for (const result of results) {
for (const poolShare of result.poolShares) { for (const poolShare of result.poolShares) {
const userShare = poolShare.balance / poolShare.poolId.totalShares const userShare = poolShare.balance / poolShare.poolId.totalShares