feat(explorer): add market specific oracle page (#5986)
This commit is contained in:
parent
475b52bcaf
commit
be9a5a3437
159
apps/explorer/src/app/components/oracle-table/index.tsx
Normal file
159
apps/explorer/src/app/components/oracle-table/index.tsx
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
import compact from 'lodash/compact';
|
||||||
|
import { MarketLink } from '../links';
|
||||||
|
import { type MarketState, MarketStateMapping } from '@vegaprotocol/types';
|
||||||
|
import OracleLink from '../links/oracle-link/oracle-link';
|
||||||
|
import type {
|
||||||
|
ExplorerOracleForMarketQuery,
|
||||||
|
ExplorerOracleFormMarketsQuery,
|
||||||
|
} from '../../routes/oracles/__generated__/OraclesForMarkets';
|
||||||
|
import { useState } from 'react';
|
||||||
|
|
||||||
|
export type OraclesTableProps = {
|
||||||
|
data?: ExplorerOracleFormMarketsQuery | ExplorerOracleForMarketQuery;
|
||||||
|
};
|
||||||
|
|
||||||
|
const cellSpacing = 'px-3';
|
||||||
|
|
||||||
|
export function OraclesTable({ data }: OraclesTableProps) {
|
||||||
|
const [hoveredOracle, setHoveredOracle] = useState('');
|
||||||
|
|
||||||
|
return (
|
||||||
|
<table className="text-left">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th className={cellSpacing}>Market</th>
|
||||||
|
<th className={cellSpacing}>Type</th>
|
||||||
|
<th className={cellSpacing}>State</th>
|
||||||
|
<th className={cellSpacing}>Settlement</th>
|
||||||
|
<th className={cellSpacing}>Termination</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{data?.marketsConnection?.edges
|
||||||
|
? data.marketsConnection.edges.map((o) => {
|
||||||
|
let hasSeenOracleReports = false;
|
||||||
|
let settlementOracle = '-';
|
||||||
|
let settlementOracleStatus = '-';
|
||||||
|
let terminationOracle = '-';
|
||||||
|
let terminationOracleStatus = '-';
|
||||||
|
|
||||||
|
const id = o?.node.id;
|
||||||
|
if (!id) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
o.node.tradableInstrument.instrument.product.__typename ===
|
||||||
|
'Future'
|
||||||
|
) {
|
||||||
|
settlementOracle =
|
||||||
|
o.node.tradableInstrument.instrument.product
|
||||||
|
.dataSourceSpecForSettlementData.id;
|
||||||
|
terminationOracle =
|
||||||
|
o.node.tradableInstrument.instrument.product
|
||||||
|
.dataSourceSpecForTradingTermination.id;
|
||||||
|
settlementOracleStatus =
|
||||||
|
o.node.tradableInstrument.instrument.product
|
||||||
|
.dataSourceSpecForSettlementData.status;
|
||||||
|
terminationOracleStatus =
|
||||||
|
o.node.tradableInstrument.instrument.product
|
||||||
|
.dataSourceSpecForTradingTermination.status;
|
||||||
|
} else if (
|
||||||
|
o.node.tradableInstrument.instrument.product.__typename ===
|
||||||
|
'Perpetual'
|
||||||
|
) {
|
||||||
|
settlementOracle =
|
||||||
|
o.node.tradableInstrument.instrument.product
|
||||||
|
.dataSourceSpecForSettlementData.id;
|
||||||
|
terminationOracle =
|
||||||
|
o.node.tradableInstrument.instrument.product
|
||||||
|
.dataSourceSpecForSettlementSchedule.id;
|
||||||
|
settlementOracleStatus =
|
||||||
|
o.node.tradableInstrument.instrument.product
|
||||||
|
.dataSourceSpecForSettlementData.status;
|
||||||
|
terminationOracleStatus =
|
||||||
|
o.node.tradableInstrument.instrument.product
|
||||||
|
.dataSourceSpecForSettlementSchedule.status;
|
||||||
|
}
|
||||||
|
const oracleInformationUnfiltered =
|
||||||
|
data?.oracleSpecsConnection?.edges?.map((e) =>
|
||||||
|
e && e.node ? e.node : undefined
|
||||||
|
) || [];
|
||||||
|
|
||||||
|
const oracleInformation = compact(oracleInformationUnfiltered)
|
||||||
|
.filter(
|
||||||
|
(o) =>
|
||||||
|
o.dataConnection.edges &&
|
||||||
|
o.dataConnection.edges.length > 0 &&
|
||||||
|
(o.dataSourceSpec.spec.id === settlementOracle ||
|
||||||
|
o.dataSourceSpec.spec.id === terminationOracle)
|
||||||
|
)
|
||||||
|
.at(0);
|
||||||
|
if (oracleInformation) {
|
||||||
|
hasSeenOracleReports = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const oracleList = `${settlementOracle} ${terminationOracle}`;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<tr
|
||||||
|
id={id}
|
||||||
|
key={id}
|
||||||
|
className={
|
||||||
|
hoveredOracle.length > 0 &&
|
||||||
|
oracleList.indexOf(hoveredOracle) > -1
|
||||||
|
? 'bg-gray-100 dark:bg-gray-800'
|
||||||
|
: ''
|
||||||
|
}
|
||||||
|
data-testid="oracle-details"
|
||||||
|
data-oracles={oracleList}
|
||||||
|
>
|
||||||
|
<td className={cellSpacing}>
|
||||||
|
<MarketLink id={id} />
|
||||||
|
</td>
|
||||||
|
<td className={cellSpacing}>
|
||||||
|
{o.node.tradableInstrument.instrument.product.__typename}
|
||||||
|
</td>
|
||||||
|
<td className={cellSpacing}>
|
||||||
|
{MarketStateMapping[o.node.state as MarketState]}
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
className={
|
||||||
|
hoveredOracle.length > 0 &&
|
||||||
|
hoveredOracle === settlementOracle
|
||||||
|
? `indent-1 ${cellSpacing}`
|
||||||
|
: cellSpacing
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<OracleLink
|
||||||
|
id={settlementOracle}
|
||||||
|
status={settlementOracleStatus}
|
||||||
|
hasSeenOracleReports={hasSeenOracleReports}
|
||||||
|
onMouseOver={() => setHoveredOracle(settlementOracle)}
|
||||||
|
onMouseOut={() => setHoveredOracle('')}
|
||||||
|
/>
|
||||||
|
</td>
|
||||||
|
<td
|
||||||
|
className={
|
||||||
|
hoveredOracle.length > 0 &&
|
||||||
|
hoveredOracle === terminationOracle
|
||||||
|
? `indent-1 ${cellSpacing}`
|
||||||
|
: cellSpacing
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<OracleLink
|
||||||
|
id={terminationOracle}
|
||||||
|
status={terminationOracleStatus}
|
||||||
|
hasSeenOracleReports={hasSeenOracleReports}
|
||||||
|
onMouseOver={() => setHoveredOracle(terminationOracle)}
|
||||||
|
onMouseOut={() => setHoveredOracle('')}
|
||||||
|
/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
: null}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
);
|
||||||
|
}
|
42
apps/explorer/src/app/routes/markets/market-oracles-page.tsx
Normal file
42
apps/explorer/src/app/routes/markets/market-oracles-page.tsx
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
import { t } from '@vegaprotocol/i18n';
|
||||||
|
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
|
||||||
|
import { useParams } from 'react-router-dom';
|
||||||
|
import { useScrollToLocation } from '../../hooks/scroll-to-location';
|
||||||
|
import { useDocumentTitle } from '../../hooks/use-document-title';
|
||||||
|
import { PageTitle } from '../../components/page-helpers/page-title';
|
||||||
|
import { useExplorerOracleForMarketQuery } from '../oracles/__generated__/OraclesForMarkets';
|
||||||
|
import { OraclesTable } from '../../components/oracle-table';
|
||||||
|
|
||||||
|
type Params = { marketId: string };
|
||||||
|
|
||||||
|
export const MarketOraclesPage = () => {
|
||||||
|
useScrollToLocation();
|
||||||
|
|
||||||
|
const { marketId } = useParams<Params>();
|
||||||
|
const { data, error, loading } = useExplorerOracleForMarketQuery({
|
||||||
|
errorPolicy: 'ignore',
|
||||||
|
variables: {
|
||||||
|
id: marketId || '1',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
useDocumentTitle([marketId ? marketId : 'market', 'Oracles for Market']);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section className="relative">
|
||||||
|
<PageTitle
|
||||||
|
data-testid="markets-heading"
|
||||||
|
title={t('Oracles for market')}
|
||||||
|
/>
|
||||||
|
<AsyncRenderer
|
||||||
|
noDataMessage={t('This chain has no markets')}
|
||||||
|
errorMessage={t('Could not fetch market') + ' ' + marketId}
|
||||||
|
data={data}
|
||||||
|
loading={loading}
|
||||||
|
error={error}
|
||||||
|
>
|
||||||
|
<OraclesTable data={data} />
|
||||||
|
</AsyncRenderer>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
};
|
@ -120,3 +120,36 @@ query ExplorerOracleFormMarkets {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
query ExplorerOracleForMarket($id: ID!) {
|
||||||
|
marketsConnection(id: $id) {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
...ExplorerOracleForMarketsMarket
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
oracleSpecsConnection {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
dataSourceSpec {
|
||||||
|
...ExplorerOracleDataSourceSpec
|
||||||
|
}
|
||||||
|
dataConnection(pagination: { last: 1 }) {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
externalData {
|
||||||
|
data {
|
||||||
|
data {
|
||||||
|
name
|
||||||
|
value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -16,6 +16,13 @@ export type ExplorerOracleFormMarketsQueryVariables = Types.Exact<{ [key: string
|
|||||||
|
|
||||||
export type ExplorerOracleFormMarketsQuery = { __typename?: 'Query', marketsConnection?: { __typename?: 'MarketConnection', edges: Array<{ __typename?: 'MarketEdge', node: { __typename?: 'Market', id: string, state: Types.MarketState, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', product: { __typename?: 'Future', dataSourceSpecForSettlementData: { __typename?: 'DataSourceSpec', id: string, status: Types.DataSourceSpecStatus }, dataSourceSpecForTradingTermination: { __typename?: 'DataSourceSpec', id: string, status: Types.DataSourceSpecStatus } } | { __typename?: 'Perpetual', dataSourceSpecForSettlementData: { __typename?: 'DataSourceSpec', id: string, status: Types.DataSourceSpecStatus }, dataSourceSpecForSettlementSchedule: { __typename?: 'DataSourceSpec', id: string, status: Types.DataSourceSpecStatus } } | { __typename?: 'Spot' } } } } }> } | null, oracleSpecsConnection?: { __typename?: 'OracleSpecsConnection', edges?: Array<{ __typename?: 'OracleSpecEdge', node: { __typename?: 'OracleSpec', dataSourceSpec: { __typename?: 'ExternalDataSourceSpec', spec: { __typename?: 'DataSourceSpec', id: string, status: Types.DataSourceSpecStatus, data: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null } | { __typename?: 'EthCallSpec', address: string, sourceChainId: number } } | { __typename?: 'DataSourceDefinitionInternal', sourceType: { __typename?: 'DataSourceSpecConfigurationTime', conditions: Array<{ __typename?: 'Condition', value?: string | null, operator: Types.ConditionOperator } | null> } | { __typename?: 'DataSourceSpecConfigurationTimeTrigger', conditions: Array<{ __typename?: 'Condition', value?: string | null, operator: Types.ConditionOperator } | null>, triggers: Array<{ __typename?: 'InternalTimeTrigger', initial?: number | null, every?: number | null } | null> } } } } }, dataConnection: { __typename?: 'OracleDataConnection', edges?: Array<{ __typename?: 'OracleDataEdge', node: { __typename?: 'OracleData', externalData: { __typename?: 'ExternalData', data: { __typename?: 'Data', data?: Array<{ __typename?: 'Property', name: string, value: string }> | null } } } } | null> | null } } } | null> | null } | null };
|
export type ExplorerOracleFormMarketsQuery = { __typename?: 'Query', marketsConnection?: { __typename?: 'MarketConnection', edges: Array<{ __typename?: 'MarketEdge', node: { __typename?: 'Market', id: string, state: Types.MarketState, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', product: { __typename?: 'Future', dataSourceSpecForSettlementData: { __typename?: 'DataSourceSpec', id: string, status: Types.DataSourceSpecStatus }, dataSourceSpecForTradingTermination: { __typename?: 'DataSourceSpec', id: string, status: Types.DataSourceSpecStatus } } | { __typename?: 'Perpetual', dataSourceSpecForSettlementData: { __typename?: 'DataSourceSpec', id: string, status: Types.DataSourceSpecStatus }, dataSourceSpecForSettlementSchedule: { __typename?: 'DataSourceSpec', id: string, status: Types.DataSourceSpecStatus } } | { __typename?: 'Spot' } } } } }> } | null, oracleSpecsConnection?: { __typename?: 'OracleSpecsConnection', edges?: Array<{ __typename?: 'OracleSpecEdge', node: { __typename?: 'OracleSpec', dataSourceSpec: { __typename?: 'ExternalDataSourceSpec', spec: { __typename?: 'DataSourceSpec', id: string, status: Types.DataSourceSpecStatus, data: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null } | { __typename?: 'EthCallSpec', address: string, sourceChainId: number } } | { __typename?: 'DataSourceDefinitionInternal', sourceType: { __typename?: 'DataSourceSpecConfigurationTime', conditions: Array<{ __typename?: 'Condition', value?: string | null, operator: Types.ConditionOperator } | null> } | { __typename?: 'DataSourceSpecConfigurationTimeTrigger', conditions: Array<{ __typename?: 'Condition', value?: string | null, operator: Types.ConditionOperator } | null>, triggers: Array<{ __typename?: 'InternalTimeTrigger', initial?: number | null, every?: number | null } | null> } } } } }, dataConnection: { __typename?: 'OracleDataConnection', edges?: Array<{ __typename?: 'OracleDataEdge', node: { __typename?: 'OracleData', externalData: { __typename?: 'ExternalData', data: { __typename?: 'Data', data?: Array<{ __typename?: 'Property', name: string, value: string }> | null } } } } | null> | null } } } | null> | null } | null };
|
||||||
|
|
||||||
|
export type ExplorerOracleForMarketQueryVariables = Types.Exact<{
|
||||||
|
id: Types.Scalars['ID'];
|
||||||
|
}>;
|
||||||
|
|
||||||
|
|
||||||
|
export type ExplorerOracleForMarketQuery = { __typename?: 'Query', marketsConnection?: { __typename?: 'MarketConnection', edges: Array<{ __typename?: 'MarketEdge', node: { __typename?: 'Market', id: string, state: Types.MarketState, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', product: { __typename?: 'Future', dataSourceSpecForSettlementData: { __typename?: 'DataSourceSpec', id: string, status: Types.DataSourceSpecStatus }, dataSourceSpecForTradingTermination: { __typename?: 'DataSourceSpec', id: string, status: Types.DataSourceSpecStatus } } | { __typename?: 'Perpetual', dataSourceSpecForSettlementData: { __typename?: 'DataSourceSpec', id: string, status: Types.DataSourceSpecStatus }, dataSourceSpecForSettlementSchedule: { __typename?: 'DataSourceSpec', id: string, status: Types.DataSourceSpecStatus } } | { __typename?: 'Spot' } } } } }> } | null, oracleSpecsConnection?: { __typename?: 'OracleSpecsConnection', edges?: Array<{ __typename?: 'OracleSpecEdge', node: { __typename?: 'OracleSpec', dataSourceSpec: { __typename?: 'ExternalDataSourceSpec', spec: { __typename?: 'DataSourceSpec', id: string, status: Types.DataSourceSpecStatus, data: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null } | { __typename?: 'EthCallSpec', address: string, sourceChainId: number } } | { __typename?: 'DataSourceDefinitionInternal', sourceType: { __typename?: 'DataSourceSpecConfigurationTime', conditions: Array<{ __typename?: 'Condition', value?: string | null, operator: Types.ConditionOperator } | null> } | { __typename?: 'DataSourceSpecConfigurationTimeTrigger', conditions: Array<{ __typename?: 'Condition', value?: string | null, operator: Types.ConditionOperator } | null>, triggers: Array<{ __typename?: 'InternalTimeTrigger', initial?: number | null, every?: number | null } | null> } } } } }, dataConnection: { __typename?: 'OracleDataConnection', edges?: Array<{ __typename?: 'OracleDataEdge', node: { __typename?: 'OracleData', externalData: { __typename?: 'ExternalData', data: { __typename?: 'Data', data?: Array<{ __typename?: 'Property', name: string, value: string }> | null } } } } | null> | null } } } | null> | null } | null };
|
||||||
|
|
||||||
export const ExplorerOracleFutureFragmentDoc = gql`
|
export const ExplorerOracleFutureFragmentDoc = gql`
|
||||||
fragment ExplorerOracleFuture on Future {
|
fragment ExplorerOracleFuture on Future {
|
||||||
dataSourceSpecForSettlementData {
|
dataSourceSpecForSettlementData {
|
||||||
@ -173,3 +180,66 @@ export function useExplorerOracleFormMarketsLazyQuery(baseOptions?: Apollo.LazyQ
|
|||||||
export type ExplorerOracleFormMarketsQueryHookResult = ReturnType<typeof useExplorerOracleFormMarketsQuery>;
|
export type ExplorerOracleFormMarketsQueryHookResult = ReturnType<typeof useExplorerOracleFormMarketsQuery>;
|
||||||
export type ExplorerOracleFormMarketsLazyQueryHookResult = ReturnType<typeof useExplorerOracleFormMarketsLazyQuery>;
|
export type ExplorerOracleFormMarketsLazyQueryHookResult = ReturnType<typeof useExplorerOracleFormMarketsLazyQuery>;
|
||||||
export type ExplorerOracleFormMarketsQueryResult = Apollo.QueryResult<ExplorerOracleFormMarketsQuery, ExplorerOracleFormMarketsQueryVariables>;
|
export type ExplorerOracleFormMarketsQueryResult = Apollo.QueryResult<ExplorerOracleFormMarketsQuery, ExplorerOracleFormMarketsQueryVariables>;
|
||||||
|
export const ExplorerOracleForMarketDocument = gql`
|
||||||
|
query ExplorerOracleForMarket($id: ID!) {
|
||||||
|
marketsConnection(id: $id) {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
...ExplorerOracleForMarketsMarket
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
oracleSpecsConnection {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
dataSourceSpec {
|
||||||
|
...ExplorerOracleDataSourceSpec
|
||||||
|
}
|
||||||
|
dataConnection(pagination: {last: 1}) {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
externalData {
|
||||||
|
data {
|
||||||
|
data {
|
||||||
|
name
|
||||||
|
value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
${ExplorerOracleForMarketsMarketFragmentDoc}
|
||||||
|
${ExplorerOracleDataSourceSpecFragmentDoc}`;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* __useExplorerOracleForMarketQuery__
|
||||||
|
*
|
||||||
|
* To run a query within a React component, call `useExplorerOracleForMarketQuery` and pass it any options that fit your needs.
|
||||||
|
* When your component renders, `useExplorerOracleForMarketQuery` returns an object from Apollo Client that contains loading, error, and data properties
|
||||||
|
* you can use to render your UI.
|
||||||
|
*
|
||||||
|
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* const { data, loading, error } = useExplorerOracleForMarketQuery({
|
||||||
|
* variables: {
|
||||||
|
* id: // value for 'id'
|
||||||
|
* },
|
||||||
|
* });
|
||||||
|
*/
|
||||||
|
export function useExplorerOracleForMarketQuery(baseOptions: Apollo.QueryHookOptions<ExplorerOracleForMarketQuery, ExplorerOracleForMarketQueryVariables>) {
|
||||||
|
const options = {...defaultOptions, ...baseOptions}
|
||||||
|
return Apollo.useQuery<ExplorerOracleForMarketQuery, ExplorerOracleForMarketQueryVariables>(ExplorerOracleForMarketDocument, options);
|
||||||
|
}
|
||||||
|
export function useExplorerOracleForMarketLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<ExplorerOracleForMarketQuery, ExplorerOracleForMarketQueryVariables>) {
|
||||||
|
const options = {...defaultOptions, ...baseOptions}
|
||||||
|
return Apollo.useLazyQuery<ExplorerOracleForMarketQuery, ExplorerOracleForMarketQueryVariables>(ExplorerOracleForMarketDocument, options);
|
||||||
|
}
|
||||||
|
export type ExplorerOracleForMarketQueryHookResult = ReturnType<typeof useExplorerOracleForMarketQuery>;
|
||||||
|
export type ExplorerOracleForMarketLazyQueryHookResult = ReturnType<typeof useExplorerOracleForMarketLazyQuery>;
|
||||||
|
export type ExplorerOracleForMarketQueryResult = Apollo.QueryResult<ExplorerOracleForMarketQuery, ExplorerOracleForMarketQueryVariables>;
|
@ -1,17 +1,10 @@
|
|||||||
import compact from 'lodash/compact';
|
|
||||||
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
|
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
|
||||||
import { RouteTitle } from '../../../components/route-title';
|
import { RouteTitle } from '../../../components/route-title';
|
||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
import { useDocumentTitle } from '../../../hooks/use-document-title';
|
import { useDocumentTitle } from '../../../hooks/use-document-title';
|
||||||
import { useScrollToLocation } from '../../../hooks/scroll-to-location';
|
import { useScrollToLocation } from '../../../hooks/scroll-to-location';
|
||||||
import { useExplorerOracleFormMarketsQuery } from '../__generated__/OraclesForMarkets';
|
import { useExplorerOracleFormMarketsQuery } from '../__generated__/OraclesForMarkets';
|
||||||
import { MarketLink } from '../../../components/links';
|
import { OraclesTable } from '../../../components/oracle-table';
|
||||||
import { OracleLink } from '../../../components/links/oracle-link/oracle-link';
|
|
||||||
import { useState } from 'react';
|
|
||||||
import { MarketStateMapping } from '@vegaprotocol/types';
|
|
||||||
import type { MarketState } from '@vegaprotocol/types';
|
|
||||||
|
|
||||||
const cellSpacing = 'px-3';
|
|
||||||
|
|
||||||
const Oracles = () => {
|
const Oracles = () => {
|
||||||
const { data, loading, error } = useExplorerOracleFormMarketsQuery({
|
const { data, loading, error } = useExplorerOracleFormMarketsQuery({
|
||||||
@ -21,8 +14,6 @@ const Oracles = () => {
|
|||||||
useDocumentTitle(['Oracles']);
|
useDocumentTitle(['Oracles']);
|
||||||
useScrollToLocation();
|
useScrollToLocation();
|
||||||
|
|
||||||
const [hoveredOracle, setHoveredOracle] = useState('');
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section>
|
<section>
|
||||||
<RouteTitle data-testid="oracle-specs-heading">{t('Oracles')}</RouteTitle>
|
<RouteTitle data-testid="oracle-specs-heading">{t('Oracles')}</RouteTitle>
|
||||||
@ -38,148 +29,7 @@ const Oracles = () => {
|
|||||||
data.oracleSpecsConnection.edges?.length === 0
|
data.oracleSpecsConnection.edges?.length === 0
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<table className="text-left">
|
<OraclesTable data={data} />
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th className={cellSpacing}>Market</th>
|
|
||||||
<th className={cellSpacing}>Type</th>
|
|
||||||
<th className={cellSpacing}>State</th>
|
|
||||||
<th className={cellSpacing}>Settlement</th>
|
|
||||||
<th className={cellSpacing}>Termination</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{data?.marketsConnection?.edges
|
|
||||||
? data.marketsConnection.edges.map((o) => {
|
|
||||||
let hasSeenOracleReports = false;
|
|
||||||
let settlementOracle = '-';
|
|
||||||
let settlementOracleStatus = '-';
|
|
||||||
let terminationOracle = '-';
|
|
||||||
let terminationOracleStatus = '-';
|
|
||||||
|
|
||||||
const id = o?.node.id;
|
|
||||||
if (!id) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
o.node.tradableInstrument.instrument.product.__typename ===
|
|
||||||
'Future'
|
|
||||||
) {
|
|
||||||
settlementOracle =
|
|
||||||
o.node.tradableInstrument.instrument.product
|
|
||||||
.dataSourceSpecForSettlementData.id;
|
|
||||||
terminationOracle =
|
|
||||||
o.node.tradableInstrument.instrument.product
|
|
||||||
.dataSourceSpecForTradingTermination.id;
|
|
||||||
settlementOracleStatus =
|
|
||||||
o.node.tradableInstrument.instrument.product
|
|
||||||
.dataSourceSpecForSettlementData.status;
|
|
||||||
terminationOracleStatus =
|
|
||||||
o.node.tradableInstrument.instrument.product
|
|
||||||
.dataSourceSpecForTradingTermination.status;
|
|
||||||
} else if (
|
|
||||||
o.node.tradableInstrument.instrument.product.__typename ===
|
|
||||||
'Perpetual'
|
|
||||||
) {
|
|
||||||
settlementOracle =
|
|
||||||
o.node.tradableInstrument.instrument.product
|
|
||||||
.dataSourceSpecForSettlementData.id;
|
|
||||||
terminationOracle =
|
|
||||||
o.node.tradableInstrument.instrument.product
|
|
||||||
.dataSourceSpecForSettlementSchedule.id;
|
|
||||||
settlementOracleStatus =
|
|
||||||
o.node.tradableInstrument.instrument.product
|
|
||||||
.dataSourceSpecForSettlementData.status;
|
|
||||||
terminationOracleStatus =
|
|
||||||
o.node.tradableInstrument.instrument.product
|
|
||||||
.dataSourceSpecForSettlementSchedule.status;
|
|
||||||
}
|
|
||||||
const oracleInformationUnfiltered =
|
|
||||||
data?.oracleSpecsConnection?.edges?.map((e) =>
|
|
||||||
e && e.node ? e.node : undefined
|
|
||||||
) || [];
|
|
||||||
|
|
||||||
const oracleInformation = compact(oracleInformationUnfiltered)
|
|
||||||
.filter(
|
|
||||||
(o) =>
|
|
||||||
o.dataConnection.edges &&
|
|
||||||
o.dataConnection.edges.length > 0 &&
|
|
||||||
(o.dataSourceSpec.spec.id === settlementOracle ||
|
|
||||||
o.dataSourceSpec.spec.id === terminationOracle)
|
|
||||||
)
|
|
||||||
.at(0);
|
|
||||||
if (oracleInformation) {
|
|
||||||
hasSeenOracleReports = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const oracleList = `${settlementOracle} ${terminationOracle}`;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<tr
|
|
||||||
id={id}
|
|
||||||
key={id}
|
|
||||||
className={
|
|
||||||
hoveredOracle.length > 0 &&
|
|
||||||
oracleList.indexOf(hoveredOracle) > -1
|
|
||||||
? 'bg-gray-100 dark:bg-gray-800'
|
|
||||||
: ''
|
|
||||||
}
|
|
||||||
data-testid="oracle-details"
|
|
||||||
data-oracles={oracleList}
|
|
||||||
>
|
|
||||||
<td className={cellSpacing}>
|
|
||||||
<MarketLink id={id} />
|
|
||||||
</td>
|
|
||||||
<td className={cellSpacing}>
|
|
||||||
{
|
|
||||||
o.node.tradableInstrument.instrument.product
|
|
||||||
.__typename
|
|
||||||
}
|
|
||||||
</td>
|
|
||||||
<td className={cellSpacing}>
|
|
||||||
{MarketStateMapping[o.node.state as MarketState]}
|
|
||||||
</td>
|
|
||||||
<td
|
|
||||||
className={
|
|
||||||
hoveredOracle.length > 0 &&
|
|
||||||
hoveredOracle === settlementOracle
|
|
||||||
? `indent-1 ${cellSpacing}`
|
|
||||||
: cellSpacing
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<OracleLink
|
|
||||||
id={settlementOracle}
|
|
||||||
status={settlementOracleStatus}
|
|
||||||
hasSeenOracleReports={hasSeenOracleReports}
|
|
||||||
onMouseOver={() => setHoveredOracle(settlementOracle)}
|
|
||||||
onMouseOut={() => setHoveredOracle('')}
|
|
||||||
/>
|
|
||||||
</td>
|
|
||||||
<td
|
|
||||||
className={
|
|
||||||
hoveredOracle.length > 0 &&
|
|
||||||
hoveredOracle === terminationOracle
|
|
||||||
? `indent-1 ${cellSpacing}`
|
|
||||||
: cellSpacing
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<OracleLink
|
|
||||||
id={terminationOracle}
|
|
||||||
status={terminationOracleStatus}
|
|
||||||
hasSeenOracleReports={hasSeenOracleReports}
|
|
||||||
onMouseOver={() =>
|
|
||||||
setHoveredOracle(terminationOracle)
|
|
||||||
}
|
|
||||||
onMouseOut={() => setHoveredOracle('')}
|
|
||||||
/>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
);
|
|
||||||
})
|
|
||||||
: null}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</AsyncRenderer>
|
</AsyncRenderer>
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
|
@ -5,9 +5,8 @@ import Home from './home';
|
|||||||
import OraclePage from './oracles';
|
import OraclePage from './oracles';
|
||||||
import Oracles from './oracles/home';
|
import Oracles from './oracles/home';
|
||||||
import { Oracle } from './oracles/id';
|
import { Oracle } from './oracles/id';
|
||||||
import Party from './parties';
|
|
||||||
import { Parties } from './parties/home';
|
import { Parties } from './parties/home';
|
||||||
import { Party as PartySingle } from './parties/id';
|
import { Party } from './parties/id';
|
||||||
import { ValidatorsPage } from './validators';
|
import { ValidatorsPage } from './validators';
|
||||||
import Genesis from './genesis';
|
import Genesis from './genesis';
|
||||||
import { Block } from './blocks/id';
|
import { Block } from './blocks/id';
|
||||||
@ -17,6 +16,7 @@ import { TxsList } from './txs/home';
|
|||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
import { Routes } from './route-names';
|
import { Routes } from './route-names';
|
||||||
import { NetworkParameters } from './network-parameters';
|
import { NetworkParameters } from './network-parameters';
|
||||||
|
import { Outlet } from 'react-router-dom';
|
||||||
import type { Params, RouteObject } from 'react-router-dom';
|
import type { Params, RouteObject } from 'react-router-dom';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import { MarketPage, MarketsPage } from './markets';
|
import { MarketPage, MarketsPage } from './markets';
|
||||||
@ -31,6 +31,7 @@ import { Disclaimer } from './pages/disclaimer';
|
|||||||
import { useFeatureFlags } from '@vegaprotocol/environment';
|
import { useFeatureFlags } from '@vegaprotocol/environment';
|
||||||
import RestrictedPage from './restricted';
|
import RestrictedPage from './restricted';
|
||||||
import { NetworkTreasury } from './treasury';
|
import { NetworkTreasury } from './treasury';
|
||||||
|
import { MarketOraclesPage } from './markets/market-oracles-page';
|
||||||
|
|
||||||
export type Navigable = {
|
export type Navigable = {
|
||||||
path: string;
|
path: string;
|
||||||
@ -67,7 +68,7 @@ export const useRouterConfig = () => {
|
|||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
path: Routes.PARTIES,
|
path: Routes.PARTIES,
|
||||||
element: <Party />,
|
element: <Outlet />,
|
||||||
handle: {
|
handle: {
|
||||||
name: t('Parties'),
|
name: t('Parties'),
|
||||||
text: t('Parties'),
|
text: t('Parties'),
|
||||||
@ -80,12 +81,12 @@ export const useRouterConfig = () => {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: ':party',
|
path: ':party',
|
||||||
element: <Party />,
|
element: <Outlet />,
|
||||||
|
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
index: true,
|
index: true,
|
||||||
element: <PartySingle />,
|
element: <Party />,
|
||||||
handle: {
|
handle: {
|
||||||
breadcrumb: (params: Params<string>) => (
|
breadcrumb: (params: Params<string>) => (
|
||||||
<Link to={linkTo(Routes.PARTIES, params.party)}>
|
<Link to={linkTo(Routes.PARTIES, params.party)}>
|
||||||
@ -96,7 +97,7 @@ export const useRouterConfig = () => {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'assets',
|
path: 'assets',
|
||||||
element: <Party />,
|
element: <Outlet />,
|
||||||
handle: {
|
handle: {
|
||||||
breadcrumb: (params: Params<string>) => (
|
breadcrumb: (params: Params<string>) => (
|
||||||
<Link to={linkTo(Routes.PARTIES, params.party)}>
|
<Link to={linkTo(Routes.PARTIES, params.party)}>
|
||||||
@ -199,6 +200,10 @@ export const useRouterConfig = () => {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: ':marketId',
|
path: ':marketId',
|
||||||
|
element: <Outlet />,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
index: true,
|
||||||
element: <MarketPage />,
|
element: <MarketPage />,
|
||||||
handle: {
|
handle: {
|
||||||
breadcrumb: (params: Params<string>) => (
|
breadcrumb: (params: Params<string>) => (
|
||||||
@ -206,6 +211,26 @@ export const useRouterConfig = () => {
|
|||||||
),
|
),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: 'oracles',
|
||||||
|
element: <Outlet />,
|
||||||
|
handle: {
|
||||||
|
breadcrumb: (params: Params<string>) => (
|
||||||
|
<MarketLink id={params.marketId as string} />
|
||||||
|
),
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
index: true,
|
||||||
|
element: <MarketOraclesPage />,
|
||||||
|
handle: {
|
||||||
|
breadcrumb: (params: Params<string>) => t('Oracles'),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
Loading…
Reference in New Issue
Block a user