diff --git a/libs/markets/src/lib/SuccessorMarket.graphql b/libs/markets/src/lib/SuccessorMarket.graphql
index 4f5255987..53c661c91 100644
--- a/libs/markets/src/lib/SuccessorMarket.graphql
+++ b/libs/markets/src/lib/SuccessorMarket.graphql
@@ -34,5 +34,8 @@ query SuccessorMarket($marketId: ID!) {
code
}
}
+ proposal {
+ id
+ }
}
}
diff --git a/libs/markets/src/lib/__generated__/SuccessorMarket.ts b/libs/markets/src/lib/__generated__/SuccessorMarket.ts
index 82bb761c3..818441a39 100644
--- a/libs/markets/src/lib/__generated__/SuccessorMarket.ts
+++ b/libs/markets/src/lib/__generated__/SuccessorMarket.ts
@@ -27,7 +27,7 @@ export type SuccessorMarketQueryVariables = Types.Exact<{
}>;
-export type SuccessorMarketQuery = { __typename?: 'Query', market?: { __typename?: 'Market', id: string, state: Types.MarketState, tradingMode: Types.MarketTradingMode, positionDecimalPlaces: number, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', name: string, code: string } } } | null };
+export type SuccessorMarketQuery = { __typename?: 'Query', market?: { __typename?: 'Market', id: string, state: Types.MarketState, tradingMode: Types.MarketTradingMode, positionDecimalPlaces: number, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', name: string, code: string } }, proposal?: { __typename?: 'Proposal', id?: string | null } | null } | null };
export const SuccessorMarketIdDocument = gql`
@@ -153,6 +153,9 @@ export const SuccessorMarketDocument = gql`
code
}
}
+ proposal {
+ id
+ }
}
}
`;
diff --git a/libs/markets/src/lib/components/market-info/market-info-accordion.tsx b/libs/markets/src/lib/components/market-info/market-info-accordion.tsx
index 17e835e96..3d91df600 100644
--- a/libs/markets/src/lib/components/market-info/market-info-accordion.tsx
+++ b/libs/markets/src/lib/components/market-info/market-info-accordion.tsx
@@ -1,4 +1,8 @@
-import { TokenStaticLinks, useEnvironment } from '@vegaprotocol/environment';
+import {
+ FLAGS,
+ TokenStaticLinks,
+ useEnvironment,
+} from '@vegaprotocol/environment';
import { removePaginationWrapper } from '@vegaprotocol/utils';
import { t } from '@vegaprotocol/i18n';
import { useDataProvider } from '@vegaprotocol/data-provider';
@@ -34,6 +38,7 @@ import {
RiskModelInfoPanel,
RiskParametersInfoPanel,
SettlementAssetInfoPanel,
+ SuccessionLineInfoPanel,
} from './market-info-panels';
import type { DataSourceDefinition } from '@vegaprotocol/types';
import isEqual from 'lodash/isEqual';
@@ -291,6 +296,13 @@ export const MarketInfoAccordion = ({
>
}
/>
+ {FLAGS.SUCCESSOR_MARKETS && (
+ }
+ />
+ )}
)}
diff --git a/libs/markets/src/lib/components/market-info/market-info-panels.spec.tsx b/libs/markets/src/lib/components/market-info/market-info-panels.spec.tsx
index b13e7c6be..98d8aa390 100644
--- a/libs/markets/src/lib/components/market-info/market-info-panels.spec.tsx
+++ b/libs/markets/src/lib/components/market-info/market-info-panels.spec.tsx
@@ -1,9 +1,11 @@
-import { render, screen } from '@testing-library/react';
+import { render, screen, waitFor } from '@testing-library/react';
import {
ConditionOperator,
ConditionOperatorMapping,
} from '@vegaprotocol/types';
-import { DataSourceProof } from './market-info-panels';
+import { DataSourceProof, SuccessionLineInfoPanel } from './market-info-panels';
+import { MockedProvider } from '@apollo/react-testing';
+import { SuccessorMarketIdsDocument } from '../../__generated__';
jest.mock('../../hooks/use-oracle-markets', () => ({
useOracleMarkets: () => [],
@@ -137,3 +139,93 @@ describe('DataSourceProof', () => {
).toBeInTheDocument();
});
});
+
+describe('SuccessionLineInfoPanel', () => {
+ const mocks = [
+ {
+ request: {
+ query: SuccessorMarketIdsDocument,
+ },
+ result: {
+ data: {
+ __typename: 'Query',
+ marketsConnection: {
+ __typename: 'MarketConnection',
+ edges: [
+ {
+ __typename: 'MarketEdge',
+ node: {
+ __typename: 'Market',
+ id: 'abc',
+ successorMarketID: 'def',
+ parentMarketID: null,
+ },
+ },
+ {
+ __typename: 'MarketEdge',
+ node: {
+ __typename: 'Market',
+ id: 'def',
+ successorMarketID: 'ghi',
+ parentMarketID: 'abc',
+ },
+ },
+ {
+ __typename: 'MarketEdge',
+ node: {
+ __typename: 'Market',
+ id: 'ghi',
+ successorMarketID: null,
+ parentMarketID: 'def',
+ },
+ },
+ ],
+ },
+ },
+ },
+ },
+ ];
+
+ it.each([
+ ['abc', 1],
+ ['def', 2],
+ ['ghi', 3],
+ ])(
+ 'renders succession line for %s (current position %d)',
+ async (id, number) => {
+ render(
+
+
+
+ );
+
+ await waitFor(() => {
+ const items = screen.getAllByTestId('succession-line-item');
+ expect(items.length).toBe(3);
+ expect(
+ items[0].querySelector(
+ '[data-testid="succession-line-item-market-id"]'
+ )?.textContent
+ ).toBe('abc');
+ expect(
+ items[1].querySelector(
+ '[data-testid="succession-line-item-market-id"]'
+ )?.textContent
+ ).toBe('def');
+ expect(
+ items[2].querySelector(
+ '[data-testid="succession-line-item-market-id"]'
+ )?.textContent
+ ).toBe('ghi');
+
+ expect(
+ items[number - 1].querySelector('[data-testid="icon-bullet"]')
+ ).toBeInTheDocument();
+ });
+ }
+ );
+});
diff --git a/libs/markets/src/lib/components/market-info/market-info-panels.tsx b/libs/markets/src/lib/components/market-info/market-info-panels.tsx
index abfb16f7a..001f562c6 100644
--- a/libs/markets/src/lib/components/market-info/market-info-panels.tsx
+++ b/libs/markets/src/lib/components/market-info/market-info-panels.tsx
@@ -1,11 +1,17 @@
import type { ReactNode } from 'react';
-import { useState } from 'react';
+import { Fragment, useState } from 'react';
import { useMemo } from 'react';
import { AssetDetailsTable, useAssetDataProvider } from '@vegaprotocol/assets';
import { t } from '@vegaprotocol/i18n';
import { marketDataProvider } from '../../market-data-provider';
import { totalFeesPercentage } from '../../market-utils';
-import { ExternalLink, Splash } from '@vegaprotocol/ui-toolkit';
+import {
+ ExternalLink,
+ Splash,
+ Tooltip,
+ VegaIcon,
+ VegaIconNames,
+} from '@vegaprotocol/ui-toolkit';
import {
addDecimalsFormatNumber,
formatNumber,
@@ -23,14 +29,26 @@ import BigNumber from 'bignumber.js';
import type { DataSourceDefinition, SignerKind } from '@vegaprotocol/types';
import { ConditionOperatorMapping } from '@vegaprotocol/types';
import { MarketTradingModeMapping } from '@vegaprotocol/types';
-import { FLAGS, useEnvironment } from '@vegaprotocol/environment';
+import {
+ DApp,
+ FLAGS,
+ TOKEN_PROPOSAL,
+ useEnvironment,
+ useLinks,
+} from '@vegaprotocol/environment';
import type { Provider } from '../../oracle-schema';
import { OracleBasicProfile } from '../../components/oracle-basic-profile';
import { useOracleProofs } from '../../hooks';
import { OracleDialog } from '../oracle-dialog/oracle-dialog';
import { useDataProvider } from '@vegaprotocol/data-provider';
-import { useParentMarketIdQuery } from '../../__generated__';
+import {
+ useParentMarketIdQuery,
+ useSuccessorMarketIdsQuery,
+ useSuccessorMarketQuery,
+} from '../../__generated__';
import { useSuccessorMarketProposalDetailsQuery } from '@vegaprotocol/proposals';
+import classNames from 'classnames';
+import compact from 'lodash/compact';
type MarketInfoProps = {
market: MarketInfo;
@@ -191,6 +209,126 @@ export const KeyDetailsInfoPanel = ({ market }: MarketInfoProps) => {
);
};
+const SuccessionLineItem = ({
+ marketId,
+ isCurrent,
+}: {
+ marketId: string;
+ isCurrent?: boolean;
+}) => {
+ const { data } = useSuccessorMarketQuery({
+ variables: {
+ marketId,
+ },
+ });
+
+ const marketData = data?.market;
+ const governanceLink = useLinks(DApp.Token);
+ const proposalLink = marketData?.proposal?.id
+ ? governanceLink(TOKEN_PROPOSAL.replace(':id', marketData?.proposal?.id))
+ : undefined;
+
+ return (
+
+
+
+ {marketData ? (
+ proposalLink ? (
+
+ {marketData.tradableInstrument.instrument.code}
+
+ ) : (
+ marketData.tradableInstrument.instrument.code
+ )
+ ) : (
+
+ )}
+
+ {isCurrent && (
+
+
+
+
+
+ )}
+
+
+ {marketData ? (
+ marketData.tradableInstrument.instrument.name
+ ) : (
+
+ )}
+
+
+ {marketId}
+
+
+ );
+};
+
+const SuccessionLink = () => (
+
+
+
+);
+
+const buildSuccessionLine = (
+ all: {
+ id: string;
+ successorMarketID?: string | null | undefined;
+ parentMarketID?: string | null | undefined;
+ }[],
+ id: string
+) => {
+ let line = [id];
+ const find = (id: string, dir?: 'up' | 'down') => {
+ const item = all.find((a) => a.id === id);
+ const anc = dir === 'up' && item?.parentMarketID;
+ const des = dir === 'down' && item?.successorMarketID;
+ if (anc) {
+ line = [anc, ...line];
+ find(anc, 'up');
+ }
+ if (des) {
+ line = [...line, des];
+ find(des, 'down');
+ }
+ };
+ find(id, 'up');
+ find(id, 'down');
+ return line;
+};
+export const SuccessionLineInfoPanel = ({
+ market,
+}: {
+ market: Pick;
+}) => {
+ const { data } = useSuccessorMarketIdsQuery();
+ const ids = compact(data?.marketsConnection?.edges.map((e) => e.node));
+ const line = buildSuccessionLine(ids, market.id);
+
+ return (
+
+ {line.map((id, i) => (
+
+ {i > 0 && }
+
+
+ ))}
+
+ );
+};
+
export const InstrumentInfoPanel = ({ market }: MarketInfoProps) => (