diff --git a/packages/api/src/index.ts b/packages/api/src/index.ts index 146d4875..246b5894 100644 --- a/packages/api/src/index.ts +++ b/packages/api/src/index.ts @@ -82,6 +82,7 @@ class DataFeedsExplorer { } this.repositories.feedRepository.setLegacyFeeds(legacyFeeds) this.repositories.feedRepository.setV2Feeds(v2Feeds) + this.repositories.feedRepository.setConfiguration(this.configuration) const web3Middleware = new Web3Middleware( this.configuration, diff --git a/packages/api/src/repository/Feed.ts b/packages/api/src/repository/Feed.ts index d0d284f0..5c546d9a 100644 --- a/packages/api/src/repository/Feed.ts +++ b/packages/api/src/repository/Feed.ts @@ -1,9 +1,16 @@ import { FeedsState } from './feedState' -import { PaginatedFeedsObject, FeedInfo, ConfigByFullName } from '../../types' +import { + PaginatedFeedsObject, + FeedInfo, + ConfigByFullName, + Network, + FeedsFilters, +} from '../../types' +import { Configuration } from '../web3Middleware/Configuration' export class FeedRepository { feedsState: FeedsState - // TODO: replace string with Network + dataFeeds: Record>> dataFeedsByNetwork: Record> configByFullName: ConfigByFullName @@ -15,15 +22,43 @@ export class FeedRepository { initialize() { const feeds = this.feedsState.listFeeds() + this.dataFeeds = feeds.reduce( + ( + acc: Record>>, + feedInfo: FeedInfo, + ) => { + let value + const isPairKeyPresent: boolean = !!acc[feedInfo.name] + const isNetworkAndPairKeyPresent: boolean = + isPairKeyPresent && !!acc[feedInfo.name][feedInfo.network] + if (isNetworkAndPairKeyPresent) { + value = [...acc[feedInfo.name][feedInfo.network], feedInfo] + } else { + value = [feedInfo] + } + return { + ...acc, + [feedInfo.name]: { + ...acc[feedInfo.name], + [feedInfo.network]: value, + }, + } + }, + {}, + ) + this.dataFeedsByNetwork = feeds.reduce( - (acc: Record>, feedInfo: FeedInfo) => ({ - ...acc, - [feedInfo.network]: acc[feedInfo.network] - ? [...acc[feedInfo.network], feedInfo] - : [feedInfo], - }), + (acc: Record>, feedInfo: FeedInfo) => { + return { + ...acc, + [feedInfo.network]: acc[feedInfo.network] + ? [...acc[feedInfo.network], feedInfo] + : [feedInfo], + } + }, {}, ) + this.configByFullName = feeds.reduce( (acc, feedInfo) => ({ ...acc, @@ -43,19 +78,63 @@ export class FeedRepository { .find((feed) => feed.feedFullName === feedFullName) } - async getFeedsByNetwork( - // starts in 1 - network: string, - ): Promise { - let feeds: Array + async getFilteredFeeds({ + network, + pair, + mainnet, + }: FeedsFilters): Promise { + let feeds: Array = [] if (network === 'all') { - feeds = Object.values(this.dataFeedsByNetwork).flat() + feeds = this.feedsState.listFeeds() + } else { + if (network && pair) { + feeds = this.dataFeeds[pair][network] + } else if (network) { + feeds = this.dataFeedsByNetwork[network] + } else if (pair) { + feeds = Object.values(this.dataFeeds[pair]).flat() + } + } + return this.getPaginatedFeedsByEnv(feeds, mainnet) + } + + getPaginatedFeedsByEnv(feeds: FeedInfo[], mainnet: boolean | null) { + if (mainnet === null) { + return { + feeds: feeds || [], + total: feeds ? feeds.length : 0, + } + } + if (mainnet) { + return this.getMainnetFeeds(feeds) } else { - feeds = this.dataFeedsByNetwork[network] + return this.getTestnetFeeds(feeds) } + } + + getConfigurationFromNetwork(network: Network) { + return this.feedsState.getConfiguration().getNetworkConfiguration(network) + } + + getTestnetFeeds(feeds: Array): PaginatedFeedsObject { + const filteredFeeds: FeedInfo[] = + feeds?.filter( + (feed) => !this.getConfigurationFromNetwork(feed.network).mainnet, + ) ?? [] return { - feeds: feeds || [], - total: feeds ? feeds.length : 0, + feeds: filteredFeeds, + total: filteredFeeds.length, + } + } + + getMainnetFeeds(feeds: Array): PaginatedFeedsObject { + const filteredFeeds: FeedInfo[] = + feeds?.filter( + (feed) => this.getConfigurationFromNetwork(feed.network).mainnet, + ) ?? [] + return { + feeds: filteredFeeds, + total: filteredFeeds.length, } } @@ -98,4 +177,9 @@ export class FeedRepository { this.feedsState.setV2Feeds(v2Feeds) this.initialize() } + + setConfiguration(configuration: Configuration) { + this.feedsState.setConfiguration(configuration) + this.initialize() + } } diff --git a/packages/api/src/repository/ResultRequest.ts b/packages/api/src/repository/ResultRequest.ts index f75041bd..2d88db8f 100644 --- a/packages/api/src/repository/ResultRequest.ts +++ b/packages/api/src/repository/ResultRequest.ts @@ -4,6 +4,7 @@ import { Db, Collection, WithoutId, + PaginatedRequests, } from '../../types' import { containFalsyValues } from './containFalsyValues' @@ -47,21 +48,49 @@ export class ResultRequestRepository { .map(this.normalizeId) } + async getFeedRequestsPageByPair( + pair: string, + page: number, + size: number, + ): Promise { + const query = { feedFullName: { $regex: pair } } + return { + requests: ( + await this.collection + .find(query) + .sort({ timestamp: -1 }) + .skip(size * (page - 1)) + .limit(size) + .toArray() + ).map(this.normalizeId), + total: (await this.collection.find(query).toArray()).length, + } + } + async getFeedRequestsPage( feedFullName: string, page: number, size: number, - ): Promise> { - return ( - await this.collection - .find({ - feedFullName, - }) - .sort({ timestamp: -1 }) - .skip(size * (page - 1)) - .limit(size) - .toArray() - ).map(this.normalizeId) + ): Promise { + return { + requests: ( + await this.collection + .find({ + feedFullName, + }) + .sort({ timestamp: -1 }) + .skip(size * (page - 1)) + .limit(size) + .toArray() + ).map(this.normalizeId), + total: ( + await this.collection + .find({ + feedFullName, + }) + .toArray() + ).length, + } } async getLastResult( diff --git a/packages/api/src/repository/feedState.ts b/packages/api/src/repository/feedState.ts index af3ec8eb..2cf50b97 100644 --- a/packages/api/src/repository/feedState.ts +++ b/packages/api/src/repository/feedState.ts @@ -1,8 +1,10 @@ import { FeedInfo } from '../../types' +import { Configuration } from '../web3Middleware/Configuration' export class FeedsState { private legacyFeeds: Array private v2Feeds: Array + private configuration: Configuration constructor() { this.legacyFeeds = [] @@ -17,10 +19,18 @@ export class FeedsState { this.legacyFeeds = legacyFeeds } + setConfiguration(configuration: Configuration) { + this.configuration = configuration + } + getV2Feeds(): Array { return this.v2Feeds } + getConfiguration(): Configuration { + return this.configuration + } + getLegacyFeeds(): Array { return this.legacyFeeds } diff --git a/packages/api/src/resolvers.ts b/packages/api/src/resolvers.ts index 777cd805..26483884 100644 --- a/packages/api/src/resolvers.ts +++ b/packages/api/src/resolvers.ts @@ -3,7 +3,11 @@ import { Context } from '../types' const resolvers = { Query: { feeds: async (_parent, args, { feedRepository }: Context) => { - return await feedRepository.getFeedsByNetwork(args.network) + return await feedRepository.getFilteredFeeds({ + network: args.network, + pair: args.pair, + mainnet: args.mainnet, + }) }, networks: (_parent, _args, { config }: Context) => { diff --git a/packages/api/src/typeDefs.ts b/packages/api/src/typeDefs.ts index d61a5edb..687363bc 100644 --- a/packages/api/src/typeDefs.ts +++ b/packages/api/src/typeDefs.ts @@ -50,6 +50,11 @@ const typeDefs = gql` timestamp: String! @column } + type PaginatedResultRequest { + requests: [ResultRequest] + total: Int! + } + # type DataRequest @entity(embedded: true) { # retrieval: String! @column # aggregation: String! @column @@ -58,8 +63,12 @@ const typeDefs = gql` type Query { feed(feedFullName: String!): Feed - feeds(network: String): FeedsPage! - requests(feedFullName: String!, page: Int!, size: Int!): [ResultRequest]! + feeds(network: String, mainnet: Boolean, pair: String): FeedsPage! + requests( + feedFullName: String! + page: Int! + size: Int! + ): PaginatedResultRequest! networks: [NetworksConfig]! } ` diff --git a/packages/api/types.ts b/packages/api/types.ts index 317e63f2..4e56a879 100644 --- a/packages/api/types.ts +++ b/packages/api/types.ts @@ -40,6 +40,10 @@ export type ConfigByFullName = { [key: string]: FeedInfo } +export type NetworkConfigByNetwork = { + [key: string]: Configuration +} + export enum Network { ArbitrumOne = 'arbitrum-one', ArbitrumGoerli = 'arbitrum-goerli', @@ -150,6 +154,11 @@ export type ResultRequestDbObjectNormalized = ResultRequestDbObject & { id: string } +export type PaginatedRequests = { + requests: Array + total: number +} + export type Repositories = { feedRepository: FeedRepository resultRequestRepository: ResultRequestRepository @@ -254,6 +263,12 @@ export type LegacyRouterDataFeedsConfig = { chains: Record } +export type FeedsFilters = { + network: string | null + pair: string | null + mainnet: boolean +} + export type FeedInfosWithoutAbis = Array< Omit > diff --git a/packages/ui/api/index.ts b/packages/ui/api/index.ts index 80cdd11e..555de3ab 100644 --- a/packages/ui/api/index.ts +++ b/packages/ui/api/index.ts @@ -4,22 +4,32 @@ import feedQuery from './queries/feed' import feedsQuery from './queries/feeds' import networksQuery from './queries/networks' import feedRequestsQuery from './queries/requests' -import type { Ecosystem, Feed, FeedRequests, Network } from '~/types' +import type { Ecosystem, Feed, FeedRequest, Network } from '~/types' function getApiEndpoint() { return useRuntimeConfig().public.apiBase } -export const getAllFeedsRequests = async ({ network }: { network: string }) => +export const getAllFeedsRequests = async ({ + network, + mainnet, + pair, +}: { + network: string | null + mainnet: boolean | null + pair: string | null +}) => (await request( getApiEndpoint(), feedsQuery, { network, + mainnet, + pair, }, { accept: 'application/json' }, )) as { - feeds: FeedRequests[] + feeds: FeedRequest[] total: number } @@ -68,8 +78,8 @@ export const getFeedRequests = async ({ feedFullName: string page: number size: number -}) => - (await request( +}) => { + const result = (await request( getApiEndpoint(), feedRequestsQuery, { @@ -79,5 +89,10 @@ export const getFeedRequests = async ({ }, { accept: 'application/json' }, )) as { - requests: FeedRequests[] + requests: { + requests: FeedRequest[] + total: number + } } + return result.requests +} diff --git a/packages/ui/api/queries/feeds.ts b/packages/ui/api/queries/feeds.ts index 9b813c63..a6b3640d 100644 --- a/packages/ui/api/queries/feeds.ts +++ b/packages/ui/api/queries/feeds.ts @@ -1,8 +1,8 @@ import { gql } from 'graphql-request' export default gql` - query feeds($network: String!) { - feeds(network: $network) { + query feeds($network: String, $mainnet: Boolean, $pair: String) { + feeds(network: $network, mainnet: $mainnet, pair: $pair) { feeds { isRouted feedFullName diff --git a/packages/ui/api/queries/requests.ts b/packages/ui/api/queries/requests.ts index f51e53e4..83611767 100644 --- a/packages/ui/api/queries/requests.ts +++ b/packages/ui/api/queries/requests.ts @@ -3,10 +3,14 @@ import { gql } from 'graphql-request' export default gql` query requests($feedFullName: String!, $page: Int!, $size: Int!) { requests(feedFullName: $feedFullName, page: $page, size: $size) { - feedFullName - result - drTxHash - timestamp + requests { + feedFullName + result + drTxHash + requestId + timestamp + } + total } } ` diff --git a/packages/ui/components/DataFeedDetails.vue b/packages/ui/components/DataFeedDetails.vue index 83d60c43..17259654 100644 --- a/packages/ui/components/DataFeedDetails.vue +++ b/packages/ui/components/DataFeedDetails.vue @@ -34,7 +34,7 @@ > @@ -57,8 +57,8 @@ :transactions="transactions" /> @@ -186,9 +186,6 @@ const maxTimeToResolve = computed(() => { } }) -const itemsLength = computed(() => { - return feed.value?.requests.length -}) const feedName = computed(() => normalizedFeed.value?.name ?? '') const networkName = computed(() => normalizedFeed.value?.networkName ?? '') @@ -209,12 +206,8 @@ const chartData: Ref[]> = computed(() => { } }) const transactions = computed(() => { - if ( - feed.value && - store.paginatedFeedRequest && - store.paginatedFeedRequest.length > 0 - ) { - return store.paginatedFeedRequest.map((request: any) => ({ + if (store.paginatedFeedRequest && store.paginatedFeedRequest.total > 0) { + return store.paginatedFeedRequest.requests.map((request) => ({ witnetLink: getWitnetBlockExplorerLink(request.drTxHash), drTxHash: request.drTxHash, data: { @@ -228,6 +221,8 @@ const transactions = computed(() => { return null } }) +const totalItems = computed(() => store.paginatedFeedRequest?.total ?? 0) + const handleCurrentChange = async (val: number) => { if (currentPage.value !== val) { currentPage.value = val diff --git a/packages/ui/components/DataFeeds.vue b/packages/ui/components/DataFeeds.vue index 1758362e..60f8a080 100644 --- a/packages/ui/components/DataFeeds.vue +++ b/packages/ui/components/DataFeeds.vue @@ -94,9 +94,11 @@ watch(networkFeeds, () => { } }) onMounted(async () => { - networkFeeds.value = await store.fetchFeeds({ + const fetchedNetworks = await store.fetchFeeds({ network: props.network.key.toLowerCase(), + mainnet: null, }) + networkFeeds.value = fetchedNetworks }) diff --git a/packages/ui/stores/index.ts b/packages/ui/stores/index.ts index 2a3540a0..ab40da7b 100644 --- a/packages/ui/stores/index.ts +++ b/packages/ui/stores/index.ts @@ -30,8 +30,16 @@ export const useStore = defineStore('data', { this.networks = (await getNetworks()).networks return this.networks }, - async fetchFeeds({ network }: { network: any }) { - return (await getAllFeedsRequests({ network })).feeds + async fetchFeeds({ + network = null, + mainnet, + pair = null, + }: { + network?: string | null + mainnet: boolean | null + pair?: string | null + }) { + return (await getAllFeedsRequests({ network, mainnet, pair })).feeds }, async fetchFeedInfo({ feedFullName, @@ -57,7 +65,7 @@ export const useStore = defineStore('data', { page, size, }) - this.paginatedFeedRequest = result.requests + this.paginatedFeedRequest = result return this.paginatedFeedRequest }, updateSelectedNetwork({ networks }: { networks: Network[] | [] }) { diff --git a/packages/ui/types.ts b/packages/ui/types.ts index a82c8377..3daacbd3 100644 --- a/packages/ui/types.ts +++ b/packages/ui/types.ts @@ -52,7 +52,7 @@ export type Ecosystem = { total: number } -export type FeedRequests = { +export type FeedRequest = { feedFullName: string result: string drTxHash: string @@ -75,7 +75,7 @@ export type Feed = { proxyAddress: string heartbeat: string finality: string - requests: FeedRequests[] + requests: FeedRequest[] blockExplorer: string color: string logo: string @@ -88,5 +88,8 @@ export interface DataStore { ecosystems: Ecosystem[] | [] totalFeeds: number feed: Feed | null - paginatedFeedRequest: FeedRequests[] | null + paginatedFeedRequest: { + requests: FeedRequest[] + total: number + } | null }