From 2453d7841a5e50b0df519a1536556db60cb216d2 Mon Sep 17 00:00:00 2001 From: Maciek Date: Tue, 12 Sep 2023 17:07:37 +0200 Subject: [PATCH 01/31] chore(trading): open connect dialog from onboarding dialog (#4744) Co-authored-by: Matthew Russell --- .../welcome-dialog/get-started.spec.tsx | 18 +--- .../components/welcome-dialog/get-started.tsx | 28 +---- .../use-get-onboarding-step.spec.tsx | 22 +--- .../welcome-dialog/use-get-onboarding-step.ts | 23 ++-- .../trading-button/trading-button.tsx | 14 +-- .../src/connect-dialog/connect-dialog.tsx | 101 +++++++++--------- .../connect-dialog/view-connector-form.tsx | 7 +- 7 files changed, 88 insertions(+), 125 deletions(-) diff --git a/apps/trading/components/welcome-dialog/get-started.spec.tsx b/apps/trading/components/welcome-dialog/get-started.spec.tsx index 01ff2dbdf..3f5c12462 100644 --- a/apps/trading/components/welcome-dialog/get-started.spec.tsx +++ b/apps/trading/components/welcome-dialog/get-started.spec.tsx @@ -22,7 +22,7 @@ describe('GetStarted', () => { }; const checkTicks = (elements: Element[]) => { elements.forEach((item, i) => { - if (i + 1 < mockStep) { + if (i + 1 < mockStep - 1) { expect(item.querySelector('[data-testid="icon-tick"]')).toBeTruthy(); } }); @@ -57,19 +57,9 @@ describe('GetStarted', () => { 'get' ); navigatorGetter.mockReturnValue('Chrome'); - mockStep = 1; - const { rerender, container } = renderComponent(); - expect(screen.queryByTestId('icon-tick')).not.toBeInTheDocument(); - expect(screen.getByTestId('get-wallet-button')).toBeInTheDocument(); mockStep = 2; - rerender( - - - - - - ); + const { rerender, container } = renderComponent(); checkTicks(screen.getAllByRole('listitem')); expect(screen.getByRole('button', { name: 'Connect' })).toBeInTheDocument(); @@ -93,7 +83,9 @@ describe('GetStarted', () => { ); checkTicks(screen.getAllByRole('listitem')); - expect(screen.getByRole('button', { name: 'Dismiss' })).toBeInTheDocument(); + expect( + screen.getByRole('button', { name: 'Ready to trade' }) + ).toBeInTheDocument(); mockStep = 5; rerender( diff --git a/apps/trading/components/welcome-dialog/get-started.tsx b/apps/trading/components/welcome-dialog/get-started.tsx index 9b6480ba5..086fdc58e 100644 --- a/apps/trading/components/welcome-dialog/get-started.tsx +++ b/apps/trading/components/welcome-dialog/get-started.tsx @@ -7,11 +7,7 @@ import { VegaIcon, VegaIconNames, } from '@vegaprotocol/ui-toolkit'; -import { - GetWalletButton, - useVegaWallet, - useVegaWalletDialogStore, -} from '@vegaprotocol/wallet'; +import { useVegaWallet, useVegaWalletDialogStore } from '@vegaprotocol/wallet'; import { Networks, useEnvironment } from '@vegaprotocol/environment'; import { useLocalStorage } from '@vegaprotocol/react-helpers'; import { useNavigate } from 'react-router-dom'; @@ -30,7 +26,6 @@ interface Props { } const GetStartedButton = ({ step }: { step: OnboardingStep }) => { - const { CHROME_EXTENSION_URL, MOZILLA_EXTENSION_URL } = useEnvironment(); const navigate = useNavigate(); const [, setOnboardingViewed] = useLocalStorage( constants.ONBOARDING_VIEWED_KEY @@ -47,15 +42,7 @@ const GetStartedButton = ({ step }: { step: OnboardingStep }) => { let onClickHandle = () => { openVegaWalletDialog(); }; - if (step === OnboardingStep.ONBOARDING_WALLET_STEP) { - return ( - - ); - } else if (step === OnboardingStep.ONBOARDING_CONNECT_STEP) { + if (step <= OnboardingStep.ONBOARDING_CONNECT_STEP) { buttonText = t('Connect'); } else if (step === OnboardingStep.ONBOARDING_DEPOSIT_STEP) { buttonText = t('Deposit'); @@ -65,7 +52,7 @@ const GetStartedButton = ({ step }: { step: OnboardingStep }) => { dismiss(); }; } else if (step === OnboardingStep.ONBOARDING_ORDER_STEP) { - buttonText = t('Dismiss'); + buttonText = t('Ready to trade'); onClickHandle = () => { navigate(link); setView({ type: ViewType.Order }); @@ -116,23 +103,18 @@ export const GetStarted = ({ lead }: Props) => {
    OnboardingStep.ONBOARDING_WALLET_STEP} - /> - OnboardingStep.ONBOARDING_CONNECT_STEP || pubKey )} /> OnboardingStep.ONBOARDING_DEPOSIT_STEP} /> OnboardingStep.ONBOARDING_ORDER_STEP} /> diff --git a/apps/trading/components/welcome-dialog/use-get-onboarding-step.spec.tsx b/apps/trading/components/welcome-dialog/use-get-onboarding-step.spec.tsx index 3c2e6d30f..d53272614 100644 --- a/apps/trading/components/welcome-dialog/use-get-onboarding-step.spec.tsx +++ b/apps/trading/components/welcome-dialog/use-get-onboarding-step.spec.tsx @@ -7,8 +7,6 @@ import { import type { VegaWalletContextShape } from '@vegaprotocol/wallet'; import { VegaWalletContext } from '@vegaprotocol/wallet'; import { useDataProvider } from '@vegaprotocol/data-provider'; -import { depositsProvider } from '@vegaprotocol/deposits'; -import { aggregatedAccountsDataProvider } from '@vegaprotocol/accounts'; import { ordersWithMarketProvider } from '@vegaprotocol/orders'; import { positionsDataProvider } from '@vegaprotocol/positions'; @@ -23,7 +21,7 @@ let mockContext: Partial = { pubKey: 'test-pubkey' }; describe('useGetOnboardingStep', () => { beforeEach(() => { jest.clearAllMocks(); - mockData = [{ id: 'item-id' }]; + mockData = []; mockContext = { pubKey: 'test-pubkey' }; globalThis.window.vega = {} as Vega; }); @@ -42,13 +40,6 @@ describe('useGetOnboardingStep', () => { expect(result.current).toEqual(OnboardingStep.ONBOARDING_UNKNOWN_STEP); }); - it('should return properly ONBOARDING_WALLET_STEP', () => { - // @ts-ignore test only purpose - globalThis.window.vega = undefined; - const { result } = renderHook(() => useGetOnboardingStep(), { wrapper }); - expect(result.current).toEqual(OnboardingStep.ONBOARDING_WALLET_STEP); - }); - it('should return properly ONBOARDING_CONNECT_STEP', () => { mockContext = { pubKey: null }; const { result } = renderHook(() => useGetOnboardingStep(), { wrapper }); @@ -56,15 +47,6 @@ describe('useGetOnboardingStep', () => { }); it('should return properly ONBOARDING_DEPOSIT_STEP', async () => { - (useDataProvider as jest.Mock).mockImplementation((args) => { - if ( - args.dataProvider === depositsProvider || - args.dataProvider === aggregatedAccountsDataProvider - ) { - return { data: [] }; - } - return { data: mockData }; - }); const { result } = renderHook(() => useGetOnboardingStep(), { wrapper }); await expect(result.current).toEqual( OnboardingStep.ONBOARDING_DEPOSIT_STEP @@ -72,6 +54,7 @@ describe('useGetOnboardingStep', () => { }); it('should return properly ONBOARDING_ORDER_STEP', async () => { + mockData = [{ id: 'item-id' }]; (useDataProvider as jest.Mock).mockImplementation((args) => { if ( args.dataProvider === ordersWithMarketProvider || @@ -86,6 +69,7 @@ describe('useGetOnboardingStep', () => { }); it('should return properly ONBOARDING_COMPLETE_STEP', async () => { + mockData = [{ id: 'item-id' }]; (useDataProvider as jest.Mock).mockImplementation(() => { return { data: mockData }; }); diff --git a/apps/trading/components/welcome-dialog/use-get-onboarding-step.ts b/apps/trading/components/welcome-dialog/use-get-onboarding-step.ts index 741def751..66adb9553 100644 --- a/apps/trading/components/welcome-dialog/use-get-onboarding-step.ts +++ b/apps/trading/components/welcome-dialog/use-get-onboarding-step.ts @@ -1,4 +1,4 @@ -import { isBrowserWalletInstalled, useVegaWallet } from '@vegaprotocol/wallet'; +import { useVegaWallet } from '@vegaprotocol/wallet'; import { depositsProvider } from '@vegaprotocol/deposits'; import { useDataProvider } from '@vegaprotocol/data-provider'; import { ordersWithMarketProvider } from '@vegaprotocol/orders'; @@ -63,20 +63,21 @@ export const useGetOnboardingStep = () => { collateralData === null || positionsData === null) ); + let step = OnboardingStep.ONBOARDING_UNKNOWN_STEP; if (isLoading) { - return OnboardingStep.ONBOARDING_UNKNOWN_STEP; - } - if (!isBrowserWalletInstalled()) { - return OnboardingStep.ONBOARDING_WALLET_STEP; + return step; } if (!pubKey) { - return OnboardingStep.ONBOARDING_CONNECT_STEP; + step = OnboardingStep.ONBOARDING_CONNECT_STEP; } - if (!deposits && !collaterals) { - return OnboardingStep.ONBOARDING_DEPOSIT_STEP; + if (pubKey) { + step = OnboardingStep.ONBOARDING_DEPOSIT_STEP; } - if (!orders && !positions) { - return OnboardingStep.ONBOARDING_ORDER_STEP; + if (pubKey && (deposits || collaterals)) { + step = OnboardingStep.ONBOARDING_ORDER_STEP; } - return OnboardingStep.ONBOARDING_COMPLETE_STEP; + if (pubKey && (orders || positions)) { + step = OnboardingStep.ONBOARDING_COMPLETE_STEP; + } + return step; }; diff --git a/libs/ui-toolkit/src/components/trading-button/trading-button.tsx b/libs/ui-toolkit/src/components/trading-button/trading-button.tsx index add985aba..48c6ac9b2 100644 --- a/libs/ui-toolkit/src/components/trading-button/trading-button.tsx +++ b/libs/ui-toolkit/src/components/trading-button/trading-button.tsx @@ -39,17 +39,17 @@ const getClassName = ( }, // colours { - 'bg-vega-yellow hover:bg-vega-yellow-550 dark:bg-vega-yellow dark:hover:bg-vega-yellow-450': + 'bg-vega-yellow enabled:hover:bg-vega-yellow-550 dark:bg-vega-yellow dark:enabled:hover:bg-vega-yellow-450': intent === Intent.Primary, - 'bg-vega-clight-500 hover:bg-vega-clight-400 dark:bg-vega-cdark-500 dark:hover:bg-vega-cdark-400': + 'bg-vega-clight-500 enabled:hover:bg-vega-clight-400 dark:bg-vega-cdark-500 dark:enabled:hover:bg-vega-cdark-400': intent === Intent.None, - 'bg-vega-blue-350 hover:bg-vega-blue-400 dark:bg-vega-blue-650 dark:hover:bg-vega-blue-600': + 'bg-vega-blue-350 enabled:hover:bg-vega-blue-400 dark:bg-vega-blue-650 dark:enabled:hover:bg-vega-blue-600': intent === Intent.Info, - 'bg-vega-orange-350 hover:bg-vega-orange-400 dark:bg-vega-orange-650 dark:hover:bg-vega-orange-600': + 'bg-vega-orange-350 enabled:hover:bg-vega-orange-400 dark:bg-vega-orange-650 dark:enabled:hover:bg-vega-orange-600': intent === Intent.Warning, - 'bg-vega-red-350 hover:bg-vega-red-400 dark:bg-vega-red-650 dark:hover:bg-vega-red-600': + 'bg-vega-red-350 enabled:hover:bg-vega-red-400 dark:bg-vega-red-650 dark:enabled:hover:bg-vega-red-600': intent === Intent.Danger, - 'bg-vega-green-350 hover:bg-vega-green-400 dark:bg-vega-green-650 dark:hover:bg-vega-green-600': + 'bg-vega-green-350 enabled:hover:bg-vega-green-400 dark:bg-vega-green-650 dark:enabled:hover:bg-vega-green-600': intent === Intent.Success, 'text-vega-clight-50 dark:text-vega-cdark-50': intent !== Intent.Primary, 'text-vega-clight-900 dark:text-vega-cdark-900': @@ -73,7 +73,7 @@ const Content = ({ children, }: Pick) => ( <> - + {children} {icon} diff --git a/libs/wallet/src/connect-dialog/connect-dialog.tsx b/libs/wallet/src/connect-dialog/connect-dialog.tsx index ab8050183..f96e5ecee 100644 --- a/libs/wallet/src/connect-dialog/connect-dialog.tsx +++ b/libs/wallet/src/connect-dialog/connect-dialog.tsx @@ -241,51 +241,49 @@ const ConnectorList = ({ 'Connect securely, deposit funds and approve or reject transactions with the Vega wallet' )}

    -
    -
    - {isBrowserWalletInstalled() ? ( - onSelect('injected')} - title={ - <> - {t('Vega Wallet')} - {' '} - {t('full featured')} - - } - description={t( - `Connect Vega Wallet extension +
    + {isBrowserWalletInstalled() ? ( + onSelect('injected')} + title={ + <> + {t('Vega Wallet')} + {' '} + {t('full featured')} + + } + description={t( + `Connect Vega Wallet extension + for %s to access all features including key + management and detailed transaction views from your + browser.`, + [browserName] + )} + /> + ) : ( +
    +

    + {t('Vega Wallet')} + {' '} + {t('full featured')} +

    +

    + {t( + `Install Vega Wallet extension for %s to access all features including key management and detailed transaction views from your browser.`, [browserName] )} +

    + - ) : ( -
    -

    - {t('Vega Wallet')} - {' '} - {t('full featured')} -

    -

    - {t( - `Install Vega Wallet extension - for %s to access all features including key - management and detailed transaction views from your - browser.`, - [browserName] - )} -

    - -
    - )} -
    +
    + )} {connectors['snap'] !== undefined ? (
    {snapStatus === SnapStatus.INSTALLED ? ( @@ -335,7 +333,7 @@ const ConnectorList = ({ }} /> {snapStatus === SnapStatus.NOT_SUPPORTED ? ( -

    +

    {t('No MetaMask version that supports snaps detected.')}{' '} {t('Learn more about')}{' '} @@ -348,7 +346,7 @@ const ConnectorList = ({

    ) : null}
    -

    {t('Advanced / Other options...')}

    +

    {t('Advanced / Other options...')}

    {title}

    -

    {description}

    +

    {description}

    {t('Custom wallet location')}

    onSelect('jsonRpc')} /> {isDesktopWalletRunning !== null && ( -

    +

    {isDesktopWalletRunning ? ( ) : ( - <> +

    {t( 'No running Desktop App/CLI detected. Open your app now to connect or enter a' @@ -636,9 +637,9 @@ const CustomUrlInput = ({ > {t('custom wallet location')} - +

    )} -

    +
    )} ); diff --git a/libs/wallet/src/connect-dialog/view-connector-form.tsx b/libs/wallet/src/connect-dialog/view-connector-form.tsx index 736e0ead7..4f3c8a791 100644 --- a/libs/wallet/src/connect-dialog/view-connector-form.tsx +++ b/libs/wallet/src/connect-dialog/view-connector-form.tsx @@ -88,10 +88,13 @@ export function ViewConnectorForm({
    )} From a77765b1e99b1ef744198d622d7702c1bbbc8e9d Mon Sep 17 00:00:00 2001 From: Matthew Russell Date: Tue, 12 Sep 2023 09:56:43 -0700 Subject: [PATCH 02/31] feat(trading): store study sizes, reduce candles gap (#4708) --- apps/trading/pages/styles.css | 1 + libs/candles-chart/src/lib/candles-chart.tsx | 31 ++++++++-- .../src/lib/use-candles-chart-settings.ts | 61 +++++++++++++++---- package.json | 2 +- yarn.lock | 8 +-- 5 files changed, 80 insertions(+), 23 deletions(-) diff --git a/apps/trading/pages/styles.css b/apps/trading/pages/styles.css index e9e1eb368..22d9a6efc 100644 --- a/apps/trading/pages/styles.css +++ b/apps/trading/pages/styles.css @@ -82,6 +82,7 @@ html [data-theme='light'] { --pennant-color-volume-sell: theme(colors.market.red.DEFAULT); + /* reduce space between candles */ --pennant-candlestick-inner-padding: 0.1; } diff --git a/libs/candles-chart/src/lib/candles-chart.tsx b/libs/candles-chart/src/lib/candles-chart.tsx index c05e79399..c0397f681 100644 --- a/libs/candles-chart/src/lib/candles-chart.tsx +++ b/libs/candles-chart/src/lib/candles-chart.tsx @@ -3,6 +3,7 @@ import { CandlestickChart } from 'pennant'; import { VegaDataSource } from './data-source'; import { useApolloClient } from '@apollo/client'; import { useMemo } from 'react'; +import debounce from 'lodash/debounce'; import AutoSizer from 'react-virtualized-auto-sizer'; import { useVegaWallet } from '@vegaprotocol/wallet'; import { useThemeSwitcher } from '@vegaprotocol/react-helpers'; @@ -22,8 +23,25 @@ export const CandlesChartContainer = ({ const { pubKey } = useVegaWallet(); const { theme } = useThemeSwitcher(); - const { interval, chartType, overlays, studies, merge } = - useCandlesChartSettings(); + const { + interval, + chartType, + overlays, + studies, + studySizes, + setStudies, + setStudySizes, + setOverlays, + } = useCandlesChartSettings(); + + const handlePaneChange = useMemo( + () => + debounce((sizes: number[]) => { + // first number is main pain, which is greedy so we don't store it + setStudySizes(sizes.filter((_, i) => i !== 0)); + }, 300), + [setStudySizes] + ); const dataSource = useMemo(() => { return new VegaDataSource(client, marketId, pubKey); @@ -45,15 +63,16 @@ export const CandlesChartContainer = ({ initialNumCandlesToDisplay: Math.floor( width * CANDLES_TO_WIDTH_FACTOR ), + studySize: 150, // default size + studySizes, }} interval={interval} theme={theme} onOptionsChanged={(options) => { - merge({ - overlays: options.overlays, - studies: options.studies, - }); + setStudies(options.studies); + setOverlays(options.overlays); }} + onPaneChanged={handlePaneChange} />
    )} diff --git a/libs/candles-chart/src/lib/use-candles-chart-settings.ts b/libs/candles-chart/src/lib/use-candles-chart-settings.ts index cce6fb5b5..c43ab4732 100644 --- a/libs/candles-chart/src/lib/use-candles-chart-settings.ts +++ b/libs/candles-chart/src/lib/use-candles-chart-settings.ts @@ -5,36 +5,45 @@ import { create } from 'zustand'; import { persist } from 'zustand/middleware'; import { immer } from 'zustand/middleware/immer'; +type StudySizes = { [S in Study]?: number }; + interface StoredSettings { interval: Interval; type: ChartType; overlays: Overlay[]; studies: Study[]; + studySizes: StudySizes; } +export const STUDY_SIZE = 100; +const STUDY_ORDER: Study[] = [ + Study.FORCE_INDEX, + Study.RELATIVE_STRENGTH_INDEX, + Study.ELDAR_RAY, + Study.MACD, + Study.VOLUME, +]; + const DEFAULT_CHART_SETTINGS = { interval: Interval.I15M, type: ChartType.CANDLE, overlays: [Overlay.MOVING_AVERAGE], studies: [Study.MACD, Study.VOLUME], + studySizes: {}, }; export const useCandlesChartSettingsStore = create< StoredSettings & { - merge: (settings: Partial) => void; setType: (type: ChartType) => void; setInterval: (interval: Interval) => void; - setOverlays: (overlays: Overlay[]) => void; - setStudies: (studies: Study[]) => void; + setOverlays: (overlays?: Overlay[]) => void; + setStudies: (studies?: Study[]) => void; + setStudySizes: (sizes: number[]) => void; } >()( persist( immer((set) => ({ ...DEFAULT_CHART_SETTINGS, - merge: (settings: Partial) => - set((state) => { - Object.assign(state, settings); - }), setType: (type) => set((state) => { state.type = type; @@ -43,14 +52,35 @@ export const useCandlesChartSettingsStore = create< set((state) => { state.interval = interval; }), - setOverlays: (overlays) => + setOverlays: (overlays) => { + if (!overlays) return; + set((state) => { state.overlays = overlays; - }), - setStudies: (studies) => + }); + }, + setStudies: (studies) => { + if (!studies) return; + + // Make sure studies are always returned in the same order + studies.sort((a, b) => { + return STUDY_ORDER.indexOf(a) - STUDY_ORDER.indexOf(b); + }); + set((state) => { state.studies = studies; - }), + }); + }, + setStudySizes: (sizes) => { + set((state) => { + // for every study find the corresonding size and update + // the size record for that study + state.studies.forEach((s, i) => { + const size = sizes[i]; + state.studySizes[s] = size; + }); + }); + }, })), { name: 'vega_candles_chart_store', @@ -85,15 +115,22 @@ export const useCandlesChartSettings = () => { [Study.VOLUME] ); + // find the study size + const studySizes = studies.map((s) => { + const size = settings.studySizes[s] || STUDY_SIZE; + return size; + }); + return { interval, chartType, overlays, studies, + studySizes, setInterval: settings.setInterval, setType: settings.setType, setStudies: settings.setStudies, setOverlays: settings.setOverlays, - merge: settings.merge, + setStudySizes: settings.setStudySizes, }; }; diff --git a/package.json b/package.json index 9cee95fdb..0938cdf05 100644 --- a/package.json +++ b/package.json @@ -70,7 +70,7 @@ "jsondiffpatch": "^0.4.1", "lodash": "^4.17.21", "next": "13.3.0", - "pennant": "1.11.1", + "pennant": "1.12.0", "react": "18.2.0", "react-copy-to-clipboard": "^5.0.4", "react-dom": "18.2.0", diff --git a/yarn.lock b/yarn.lock index 8b074a557..9c0a29346 100644 --- a/yarn.lock +++ b/yarn.lock @@ -20253,10 +20253,10 @@ pend@~1.2.0: resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" integrity sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg== -pennant@1.11.1: - version "1.11.1" - resolved "https://registry.yarnpkg.com/pennant/-/pennant-1.11.1.tgz#f47bceaade01db215eeba666cd755840d16fe9ed" - integrity sha512-U26OxjxETWLJAvCFj20oH0y5gzyBfJ5oD4O3dYg1aWnH4giUYDPWuUDFnzlMJ+yXolyYECccXm6S1BkoVcVzDg== +pennant@1.12.0: + version "1.12.0" + resolved "https://registry.yarnpkg.com/pennant/-/pennant-1.12.0.tgz#e12707d5f1aac554d81bad060637e608335e0b50" + integrity sha512-xosg5erRf+Ke9iORdqyv+SOGcD3uJX1dgf990q1DvHuzz36w2txCZsfnvcXhRO++HYVKS9sU/YLPRLJgolFGtA== dependencies: "@babel/runtime" "^7.13.10" "@d3fc/d3fc-technical-indicator" "^8.0.1" From 293288286b6782f0bb795c1a83a8391867c31acb Mon Sep 17 00:00:00 2001 From: Maciek Date: Tue, 12 Sep 2023 18:59:13 +0200 Subject: [PATCH 03/31] chore(trading): adjust gap between candles (#4753) --- apps/trading/pages/styles.css | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/trading/pages/styles.css b/apps/trading/pages/styles.css index 22d9a6efc..e4e2d4659 100644 --- a/apps/trading/pages/styles.css +++ b/apps/trading/pages/styles.css @@ -83,7 +83,8 @@ html [data-theme='light'] { --pennant-color-volume-sell: theme(colors.market.red.DEFAULT); /* reduce space between candles */ - --pennant-candlestick-inner-padding: 0.1; + --pennant-candlestick-inner-padding: 0.175; + --pennant-candlestick-stroke-width: 0.5; } html [data-theme='light'] { From 41804d98695a510fb8b36dc0b2441d5349c76ee5 Mon Sep 17 00:00:00 2001 From: Art Date: Tue, 12 Sep 2023 19:41:45 +0200 Subject: [PATCH 04/31] chore(trading): market list tweaks (#4756) Co-authored-by: Matthew Russell --- .../src/lib/cells/market-name-cell.tsx | 4 +- .../markets-container.spec.tsx | 35 +--- .../markets-container/markets-container.tsx | 10 +- .../markets-container/use-column-defs.tsx | 176 ++++++++++-------- 4 files changed, 114 insertions(+), 111 deletions(-) diff --git a/libs/datagrid/src/lib/cells/market-name-cell.tsx b/libs/datagrid/src/lib/cells/market-name-cell.tsx index d1df34e5d..0d7ffb8a7 100644 --- a/libs/datagrid/src/lib/cells/market-name-cell.tsx +++ b/libs/datagrid/src/lib/cells/market-name-cell.tsx @@ -59,7 +59,7 @@ export const MarketNameCell = ({ (data as { market: Market })?.market?.tradableInstrument.instrument.product .__typename; - if (!value) return; + if (!value) return null; const content = ( <> @@ -72,7 +72,7 @@ export const MarketNameCell = ({ diff --git a/libs/markets/src/lib/components/markets-container/markets-container.spec.tsx b/libs/markets/src/lib/components/markets-container/markets-container.spec.tsx index 34e2d74e0..fe88d1dbc 100644 --- a/libs/markets/src/lib/components/markets-container/markets-container.spec.tsx +++ b/libs/markets/src/lib/components/markets-container/markets-container.spec.tsx @@ -83,8 +83,9 @@ describe('MarketsContainer', () => { await userEvent.click( screen.getByRole('button', { name: (_name, element) => - (element.parentNode as Element)?.getAttribute('id') === - 'cell-market-actions-9', + (element.parentNode as Element) + ?.getAttribute('id') + ?.startsWith('cell-market-actions-') || false, }) ); @@ -126,36 +127,6 @@ describe('MarketsContainer', () => { } }); - it('SuccessorMarketRenderer should be rendered', async () => { - const successorMarketName = 'Successor Market Name'; - const spySuccessorMarketRenderer = jest - .fn() - .mockReturnValue(successorMarketName); - - render( - - - - ); - - expect(spySuccessorMarketRenderer).toHaveBeenCalled(); - expect( - screen.getByRole('columnheader', { - name: (_name, element) => - element.getAttribute('col-id') === 'successorMarketID', - }) - ).toBeInTheDocument(); - expect( - screen.getByRole('presentation', { - name: (_name, element) => - element.getAttribute('id') === 'cell-successorMarketID-14', - }) - ).toHaveTextContent(successorMarketName); - }); - it('feature flag should hide successorMarketID column', async () => { const mockedFlags = jest.mocked(FLAGS); mockedFlags.SUCCESSOR_MARKETS = false; diff --git a/libs/markets/src/lib/components/markets-container/markets-container.tsx b/libs/markets/src/lib/components/markets-container/markets-container.tsx index 8a8d39fb9..826bd0aac 100644 --- a/libs/markets/src/lib/components/markets-container/markets-container.tsx +++ b/libs/markets/src/lib/components/markets-container/markets-container.tsx @@ -4,8 +4,10 @@ import type { CellClickedEvent } from 'ag-grid-community'; import { t } from '@vegaprotocol/i18n'; import { MarketListTable } from './market-list-table'; import { useDataProvider } from '@vegaprotocol/data-provider'; -import { marketsWithDataProvider as dataProvider } from '../../markets-provider'; +import { marketListProvider as dataProvider } from '../../markets-provider'; import type { MarketMaybeWithData } from '../../markets-provider'; +import { useYesterday } from '@vegaprotocol/react-helpers'; +import { Interval } from '@vegaprotocol/types'; const POLLING_TIME = 2000; interface MarketsContainerProps { @@ -17,9 +19,13 @@ export const MarketsContainer = ({ onSelect, SuccessorMarketRenderer, }: MarketsContainerProps) => { + const yesterday = useYesterday(); const { data, error, reload } = useDataProvider({ dataProvider, - variables: undefined, + variables: { + since: new Date(yesterday).toISOString(), + interval: Interval.INTERVAL_I1H, + }, }); useEffect(() => { diff --git a/libs/markets/src/lib/components/markets-container/use-column-defs.tsx b/libs/markets/src/lib/components/markets-container/use-column-defs.tsx index 4271debcd..a0511303c 100644 --- a/libs/markets/src/lib/components/markets-container/use-column-defs.tsx +++ b/libs/markets/src/lib/components/markets-container/use-column-defs.tsx @@ -1,5 +1,5 @@ import { useMemo } from 'react'; -import type { ColDef } from 'ag-grid-community'; +import type { ColDef, ValueFormatterParams } from 'ag-grid-community'; import compact from 'lodash/compact'; import { t } from '@vegaprotocol/i18n'; import type { @@ -10,11 +10,14 @@ import type { import { COL_DEFS, SetFilter } from '@vegaprotocol/datagrid'; import * as Schema from '@vegaprotocol/types'; import { addDecimalsFormatNumber, toBigNum } from '@vegaprotocol/utils'; -import { ButtonLink } from '@vegaprotocol/ui-toolkit'; +import { ButtonLink, Tooltip } from '@vegaprotocol/ui-toolkit'; import { useAssetDetailsDialogStore } from '@vegaprotocol/assets'; -import { FLAGS } from '@vegaprotocol/environment'; -import type { MarketMaybeWithData } from '../../markets-provider'; +import type { + MarketMaybeWithData, + MarketMaybeWithDataAndCandles, +} from '../../markets-provider'; import { MarketActionsDropdown } from './market-table-actions'; +import { calcCandleVolume } from '../../market-utils'; interface Props { onMarketClick: (marketId: string, metaKey?: boolean) => void; @@ -32,26 +35,42 @@ export const useColumnDefs = ({ onMarketClick }: Props) => { field: 'tradableInstrument.instrument.code', cellRenderer: 'MarketName', cellRendererParams: { onMarketClick }, + flex: 2, }, { headerName: t('Description'), field: 'tradableInstrument.instrument.name', + flex: 2, }, { headerName: t('Trading mode'), field: 'tradingMode', - valueFormatter: ({ + cellRenderer: ({ data, - }: VegaValueFormatterParams) => { + }: VegaICellRendererParams) => { if (!data?.data) return '-'; const { trigger, marketTradingMode } = data.data; - return marketTradingMode === - MarketTradingMode.TRADING_MODE_MONITORING_AUCTION && + + const withTriggerInfo = + marketTradingMode === + MarketTradingMode.TRADING_MODE_MONITORING_AUCTION && trigger && - trigger !== AuctionTrigger.AUCTION_TRIGGER_UNSPECIFIED - ? `${Schema.MarketTradingModeMapping[marketTradingMode]} - - ${Schema.AuctionTriggerMapping[trigger]}` - : Schema.MarketTradingModeMapping[marketTradingMode]; + trigger !== AuctionTrigger.AUCTION_TRIGGER_UNSPECIFIED; + + if (withTriggerInfo) { + return ( + + + {Schema.MarketTradingModeMapping[marketTradingMode]} + + + ); + } + + return Schema.MarketTradingModeMapping[marketTradingMode]; }, filter: SetFilter, filterParams: { @@ -71,69 +90,6 @@ export const useColumnDefs = ({ onMarketClick }: Props) => { set: Schema.MarketStateMapping, }, }, - FLAGS.SUCCESSOR_MARKETS && { - headerName: t('Successor market'), - field: 'successorMarketID', - cellRenderer: 'SuccessorMarketRenderer', - }, - { - headerName: t('Best bid'), - field: 'data.bestBidPrice', - type: 'rightAligned', - cellRenderer: 'PriceFlashCell', - filter: 'agNumberColumnFilter', - valueGetter: ({ - data, - }: VegaValueGetterParams) => { - return data?.data?.bestBidPrice === undefined - ? undefined - : toBigNum( - data?.data?.bestBidPrice, - data.decimalPlaces - ).toNumber(); - }, - valueFormatter: ({ - data, - }: VegaValueFormatterParams< - MarketMaybeWithData, - 'data.bestBidPrice' - >) => - data?.data?.bestBidPrice === undefined - ? '-' - : addDecimalsFormatNumber( - data.data.bestBidPrice, - data.decimalPlaces - ), - }, - { - headerName: t('Best offer'), - field: 'data.bestOfferPrice', - type: 'rightAligned', - cellRenderer: 'PriceFlashCell', - filter: 'agNumberColumnFilter', - valueGetter: ({ - data, - }: VegaValueGetterParams) => { - return data?.data?.bestOfferPrice === undefined - ? undefined - : toBigNum( - data?.data?.bestOfferPrice, - data.decimalPlaces - ).toNumber(); - }, - valueFormatter: ({ - data, - }: VegaValueFormatterParams< - MarketMaybeWithData, - 'data.bestOfferPrice' - >) => - data?.data?.bestOfferPrice === undefined - ? '-' - : addDecimalsFormatNumber( - data.data.bestOfferPrice, - data.decimalPlaces - ), - }, { headerName: t('Mark price'), field: 'data.markPrice', @@ -157,6 +113,33 @@ export const useColumnDefs = ({ onMarketClick }: Props) => { data.decimalPlaces ), }, + { + headerName: t('24h volume'), + type: 'rightAligned', + field: 'data.candles', + valueGetter: ({ + data, + }: VegaValueGetterParams) => { + if (!data) return 0; + const candles = data?.candles; + const vol = candles ? calcCandleVolume(candles) : '0'; + return Number(vol); + }, + valueFormatter: ({ + data, + }: ValueFormatterParams< + MarketMaybeWithDataAndCandles, + 'candles' + >) => { + const candles = data?.candles; + const vol = candles ? calcCandleVolume(candles) : '0'; + const volume = + data && vol && vol !== '0' + ? addDecimalsFormatNumber(vol, data.positionDecimalPlaces) + : '0.00'; + return volume; + }, + }, { headerName: t('Settlement asset'), field: 'tradableInstrument.instrument.product.settlementAsset.symbol', @@ -181,6 +164,49 @@ export const useColumnDefs = ({ onMarketClick }: Props) => { ); }, }, + { + headerName: t('Spread'), + field: 'data.bestBidPrice', + type: 'rightAligned', + filter: 'agNumberColumnFilter', + cellRenderer: 'PriceFlashCell', + valueGetter: ({ + data, + }: VegaValueGetterParams) => { + if ( + !data || + !data.data?.bestOfferPrice || + !data.data?.bestBidPrice + ) { + return undefined; + } + + const offer = toBigNum( + data.data.bestOfferPrice, + data.decimalPlaces + ); + const bid = toBigNum(data.data.bestBidPrice, data.decimalPlaces); + + const spread = offer.minus(bid).toNumber(); + + // The calculation above can result in '-0' being rendered after formatting + // so return Math.abs to remove it and just render '0' + if (spread === 0) { + return Math.abs(spread); + } + + return spread; + }, + valueFormatter: ({ + value, + }: VegaValueFormatterParams< + MarketMaybeWithData, + 'data.bestBidPrice' + >) => { + if (!value) return '-'; + return value.toString(); + }, + }, { colId: 'market-actions', field: 'id', From 27e8ce88bf3e32f7fd93fd83cfff6565e9e55b35 Mon Sep 17 00:00:00 2001 From: Maciek Date: Tue, 12 Sep 2023 20:10:17 +0200 Subject: [PATCH 05/31] chore(trading): adjust onboarding experience (#4754) --- .../market-selector/market-selector.spec.tsx | 2 +- .../use-market-selector-list.spec.tsx | 10 +++---- .../use-market-selector-list.ts | 13 +--------- .../welcome-dialog/welcome-dialog-content.tsx | 26 ++++++++++++++++--- apps/trading/lib/utils/index.ts | 12 +++++++++ 5 files changed, 40 insertions(+), 23 deletions(-) create mode 100644 apps/trading/lib/utils/index.ts diff --git a/apps/trading/components/market-selector/market-selector.spec.tsx b/apps/trading/components/market-selector/market-selector.spec.tsx index f4cfadda6..588d78b7d 100644 --- a/apps/trading/components/market-selector/market-selector.spec.tsx +++ b/apps/trading/components/market-selector/market-selector.spec.tsx @@ -10,7 +10,7 @@ import type { SortType } from './sort-dropdown'; import { SortTypeMapping } from './sort-dropdown'; import { Sort } from './sort-dropdown'; import { subDays } from 'date-fns'; -import { isMarketActive } from './use-market-selector-list'; +import { isMarketActive } from '../../lib/utils'; jest.mock('@vegaprotocol/markets'); const mockUseMarketList = useMarketList as jest.Mock; diff --git a/apps/trading/components/market-selector/use-market-selector-list.spec.tsx b/apps/trading/components/market-selector/use-market-selector-list.spec.tsx index 5297dafc4..05dfa3836 100644 --- a/apps/trading/components/market-selector/use-market-selector-list.spec.tsx +++ b/apps/trading/components/market-selector/use-market-selector-list.spec.tsx @@ -1,15 +1,13 @@ import merge from 'lodash/merge'; import { renderHook } from '@testing-library/react'; -import { - isMarketActive, - useMarketSelectorList, -} from './use-market-selector-list'; -import { Product } from '../../components/market-selector/product-selector'; +import { useMarketSelectorList } from './use-market-selector-list'; +import { isMarketActive } from '../../lib/utils'; +import { Product } from './product-selector'; import { Sort } from './sort-dropdown'; import { createMarketFragment } from '@vegaprotocol/mock'; import { MarketState } from '@vegaprotocol/types'; import { useMarketList } from '@vegaprotocol/markets'; -import type { Filter } from '../../components/market-selector'; +import type { Filter } from './market-selector'; import { subDays } from 'date-fns'; jest.mock('@vegaprotocol/markets', () => ({ diff --git a/apps/trading/components/market-selector/use-market-selector-list.ts b/apps/trading/components/market-selector/use-market-selector-list.ts index 47f68e4c8..f22a3ca09 100644 --- a/apps/trading/components/market-selector/use-market-selector-list.ts +++ b/apps/trading/components/market-selector/use-market-selector-list.ts @@ -1,18 +1,11 @@ import { useMemo } from 'react'; import orderBy from 'lodash/orderBy'; -import { MarketState } from '@vegaprotocol/types'; import { calcTradedFactor, useMarketList } from '@vegaprotocol/markets'; import { priceChangePercentage } from '@vegaprotocol/utils'; import type { Filter } from '../../components/market-selector/market-selector'; import { Sort } from './sort-dropdown'; import { Product } from './product-selector'; - -// Used for sort order and filter -const MARKET_TEMPLATE = [ - MarketState.STATE_ACTIVE, - MarketState.STATE_SUSPENDED, - MarketState.STATE_PENDING, -]; +import { isMarketActive } from '../../lib/utils'; export const useMarketSelectorList = ({ product, @@ -87,7 +80,3 @@ export const useMarketSelectorList = ({ return { markets, data, loading, error, reload }; }; - -export const isMarketActive = (state: MarketState) => { - return MARKET_TEMPLATE.includes(state); -}; diff --git a/apps/trading/components/welcome-dialog/welcome-dialog-content.tsx b/apps/trading/components/welcome-dialog/welcome-dialog-content.tsx index 7e9564de4..1a2cedff6 100644 --- a/apps/trading/components/welcome-dialog/welcome-dialog-content.tsx +++ b/apps/trading/components/welcome-dialog/welcome-dialog-content.tsx @@ -6,14 +6,32 @@ import { Links, Routes } from '../../pages/client-router'; import { Networks, useEnvironment } from '@vegaprotocol/environment'; import type { ReactNode } from 'react'; import { useOnboardingStore } from './welcome-dialog'; +import { useMarketList } from '@vegaprotocol/markets'; +import { isMarketActive } from '../../lib/utils'; +import orderBy from 'lodash/orderBy'; +import { priceChangePercentage } from '@vegaprotocol/utils'; export const WelcomeDialogContent = () => { const { VEGA_ENV } = useEnvironment(); const dismiss = useOnboardingStore((store) => store.dismiss); const navigate = useNavigate(); - const browseMarkets = () => { - const link = Links[Routes.MARKETS](); + const { data } = useMarketList(); + const markets = orderBy( + data?.filter((m) => isMarketActive(m.state)) || [], + [ + (m) => { + if (!m.candles?.length) return 0; + return Number(priceChangePercentage(m.candles.map((c) => c.close))); + }, + ], + ['desc'] + ); + const explore = () => { + const marketId = markets?.[0].id ?? ''; + const link = marketId + ? Links[Routes.MARKET](marketId) + : Links[Routes.MARKETS](); navigate(link); dismiss(); }; @@ -48,11 +66,11 @@ export const WelcomeDialogContent = () => { />
- {t('Browse the markets')} + {t('Explore')}
diff --git a/apps/trading/lib/utils/index.ts b/apps/trading/lib/utils/index.ts new file mode 100644 index 000000000..95c3e7329 --- /dev/null +++ b/apps/trading/lib/utils/index.ts @@ -0,0 +1,12 @@ +import { MarketState } from '@vegaprotocol/types'; + +// Used for sort order and filter +const MARKET_TEMPLATE = [ + MarketState.STATE_ACTIVE, + MarketState.STATE_SUSPENDED, + MarketState.STATE_PENDING, +]; + +export const isMarketActive = (state: MarketState) => { + return MARKET_TEMPLATE.includes(state); +}; From ccbe34e1720d34486c3514c8ba06229c3b5d9d41 Mon Sep 17 00:00:00 2001 From: Art Date: Tue, 12 Sep 2023 20:26:54 +0200 Subject: [PATCH 06/31] chore(trading): make deal ticket open on market change (#4749) --- apps/trading/client-pages/market/market.tsx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/trading/client-pages/market/market.tsx b/apps/trading/client-pages/market/market.tsx index 2175a48c2..72bad717e 100644 --- a/apps/trading/client-pages/market/market.tsx +++ b/apps/trading/client-pages/market/market.tsx @@ -69,15 +69,15 @@ export const MarketPage = () => { useEffect(() => { if (data?.id && data.id !== lastMarketId) { update({ marketId: data.id }); - } - }, [update, lastMarketId, data?.id]); - - // Make sidebar open on deal ticket by default - useEffect(() => { - if (init && view === null) { + // make sidebar open on market id change setView({ type: ViewType.Order }); } - }, [init, view, setView]); + + // make sidebar open on deal ticket by default + if (view === null) { + setView({ type: ViewType.Order }); + } + }, [update, lastMarketId, data?.id, setView, init, view]); const tradeView = useMemo(() => { if (largeScreen) { From 7f5e8ebb15049264ee8559a43c898513b63c9d90 Mon Sep 17 00:00:00 2001 From: Matthew Russell Date: Tue, 12 Sep 2023 11:52:03 -0700 Subject: [PATCH 07/31] chore(trading): replace successor cols with market code cell (#4722) --- .../client-pages/markets/closed.spec.tsx | 229 ++--------------- apps/trading/client-pages/markets/closed.tsx | 57 ++--- .../markets/market-code-cell.spec.tsx | 82 +++++++ .../client-pages/markets/market-code-cell.tsx | 51 ++++ .../markets/market-list-table.tsx | 35 +++ .../markets}/market-table-actions.tsx | 27 ++ .../client-pages/markets/markets-page.tsx | 4 +- apps/trading/client-pages/markets/markets.tsx | 13 - .../client-pages/markets/open-markets.tsx | 63 +++++ .../client-pages/markets/oracle-status.tsx | 46 ++++ .../markets/parent-market-cell.tsx | 15 ++ .../trading/client-pages/markets/proposed.tsx | 8 +- .../markets/successor-market-cell.spec.tsx | 190 -------------- .../markets/successor-market-cell.tsx | 41 ---- .../client-pages/markets/use-column-defs.tsx | 226 +++++++++++++++++ .../lib/hooks/use-market-click-handler.ts | 24 +- libs/datagrid/src/index.ts | 1 + .../src/lib/cells}/stacked-cell.tsx | 0 libs/markets/src/lib/__generated__/markets.ts | 6 +- libs/markets/src/lib/components/index.ts | 1 - .../lib/components/markets-container/index.ts | 2 - .../markets-container/market-list-table.tsx | 69 ------ .../markets-container.spec.tsx | 150 ------------ .../markets-container/markets-container.tsx | 72 ------ .../markets-container/oracle-status.tsx | 44 ---- .../markets-container/summary-cell.tsx | 29 --- .../markets-container/use-column-defs.tsx | 231 ------------------ .../oracle-basic-profile.tsx | 9 +- libs/markets/src/lib/markets-provider.ts | 33 --- libs/markets/src/lib/markets.graphql | 2 + libs/markets/src/lib/markets.mock.ts | 2 + libs/positions/src/lib/positions-table.tsx | 2 +- .../proposals-list/proposal-list.spec.tsx | 181 ++++---------- .../proposals-list/proposals-list.tsx | 27 +- .../proposals-list/use-column-defs.tsx | 99 +++----- .../proposals-data-provider/Proposals.graphql | 3 + .../__generated__/Proposals.ts | 9 +- .../proposals-data-provider/proposals.mock.ts | 101 ++++---- 38 files changed, 782 insertions(+), 1402 deletions(-) create mode 100644 apps/trading/client-pages/markets/market-code-cell.spec.tsx create mode 100644 apps/trading/client-pages/markets/market-code-cell.tsx create mode 100644 apps/trading/client-pages/markets/market-list-table.tsx rename {libs/markets/src/lib/components/markets-container => apps/trading/client-pages/markets}/market-table-actions.tsx (60%) delete mode 100644 apps/trading/client-pages/markets/markets.tsx create mode 100644 apps/trading/client-pages/markets/open-markets.tsx create mode 100644 apps/trading/client-pages/markets/oracle-status.tsx create mode 100644 apps/trading/client-pages/markets/parent-market-cell.tsx delete mode 100644 apps/trading/client-pages/markets/successor-market-cell.spec.tsx delete mode 100644 apps/trading/client-pages/markets/successor-market-cell.tsx create mode 100644 apps/trading/client-pages/markets/use-column-defs.tsx rename libs/{positions/src/lib => datagrid/src/lib/cells}/stacked-cell.tsx (100%) delete mode 100644 libs/markets/src/lib/components/markets-container/index.ts delete mode 100644 libs/markets/src/lib/components/markets-container/market-list-table.tsx delete mode 100644 libs/markets/src/lib/components/markets-container/markets-container.spec.tsx delete mode 100644 libs/markets/src/lib/components/markets-container/markets-container.tsx delete mode 100644 libs/markets/src/lib/components/markets-container/oracle-status.tsx delete mode 100644 libs/markets/src/lib/components/markets-container/summary-cell.tsx delete mode 100644 libs/markets/src/lib/components/markets-container/use-column-defs.tsx diff --git a/apps/trading/client-pages/markets/closed.spec.tsx b/apps/trading/client-pages/markets/closed.spec.tsx index 85f302be9..d5482ba26 100644 --- a/apps/trading/client-pages/markets/closed.spec.tsx +++ b/apps/trading/client-pages/markets/closed.spec.tsx @@ -1,4 +1,4 @@ -import { act, render, screen, within, waitFor } from '@testing-library/react'; +import { act, render, screen, within } from '@testing-library/react'; import { MemoryRouter } from 'react-router-dom'; import { Closed } from './closed'; import { MarketStateMapping, PropertyKeyType } from '@vegaprotocol/types'; @@ -10,55 +10,21 @@ import type { OracleSpecDataConnectionQuery, MarketsDataQuery, MarketsQuery, - SuccessorMarketIdsQuery, } from '@vegaprotocol/markets'; import { OracleSpecDataConnectionDocument, MarketsDataDocument, MarketsDocument, - SuccessorMarketIdsDocument, } from '@vegaprotocol/markets'; import type { VegaWalletContextShape } from '@vegaprotocol/wallet'; import { VegaWalletContext } from '@vegaprotocol/wallet'; import { addDecimalsFormatNumber } from '@vegaprotocol/utils'; -import { FLAGS } from '@vegaprotocol/environment'; import { createMarketFragment, marketsQuery, marketsDataQuery, createMarketsDataFragment, } from '@vegaprotocol/mock'; -import type { FeatureFlags } from '@vegaprotocol/environment'; - -jest.mock('@vegaprotocol/markets', () => ({ - ...jest.requireActual('@vegaprotocol/markets'), - useSuccessorMarket: (marketId: string) => - marketId === 'include-0' - ? { - data: { - id: 'successorMarketID', - state: 'STATE_ACTIVE', - tradableInstrument: { - instrument: { - name: 'Successor Market Name', - code: 'SuccessorCode', - }, - }, - }, - } - : { data: undefined }, -})); - -jest.mock('@vegaprotocol/environment', () => { - const actual = jest.requireActual('@vegaprotocol/environment'); - return { - ...actual, - FLAGS: { - ...actual.FLAGS, - SUCCESSOR_MARKETS: true, - } as FeatureFlags, - }; -}); describe('Closed', () => { let originalNow: typeof Date.now; @@ -218,10 +184,8 @@ describe('Closed', () => { const headers = screen.getAllByRole('columnheader'); const expectedHeaders = [ 'Market', - 'Description', 'Status', 'Settlement date', - 'Successor market', 'Best bid', 'Best offer', 'Mark price', @@ -235,10 +199,8 @@ describe('Closed', () => { const cells = screen.getAllByRole('gridcell'); const expectedValues = [ market.tradableInstrument.instrument.code, - market.tradableInstrument.instrument.name, MarketStateMapping[market.state], '3 days ago', - '-', /* eslint-disable @typescript-eslint/no-non-null-assertion */ addDecimalsFormatNumber(marketsData.bestBidPrice, market.decimalPlaces), addDecimalsFormatNumber( @@ -340,43 +302,26 @@ describe('Closed', () => { .getAllByRole('gridcell') .filter((cell) => cell.getAttribute('col-id') === 'code') .map((cell) => { - const marketId = within(cell) - .getByTestId('market-code') - .getAttribute('data-market-id'); - return marketId; + const marketCode = within(cell).getByTestId('stack-cell-primary'); + return marketCode.textContent; }); - expect(cells).toEqual(expectedRows.map((m) => m.node.id)); + expect(cells).toEqual( + expectedRows.map((m) => m.node.tradableInstrument.instrument.code) + ); }); it('successor marked should be visible', async () => { - const mixedMarkets = [ + const marketsWithSuccessorID = [ { __typename: 'MarketEdge' as const, node: createMarketFragment({ id: 'include-0', state: MarketState.STATE_SETTLED, + successorMarketID: 'successor', }), }, - { - __typename: 'MarketEdge' as const, - node: { - ...createMarketFragment({ - id: 'successorMarketID', - state: MarketState.STATE_ACTIVE, - }), - tradableInstrument: { - ...createMarketFragment().tradableInstrument, - instrument: { - ...createMarketFragment().tradableInstrument.instrument, - id: 'successorAssset', - name: 'Successor Market Name', - code: 'SuccessorCode', - }, - }, - }, - }, ]; - const mixedMarketsMock: MockedResponse = { + const mockWithSuccessors: MockedResponse = { request: { query: MarketsDocument, }, @@ -384,42 +329,17 @@ describe('Closed', () => { data: { marketsConnection: { __typename: 'MarketConnection', - edges: mixedMarkets, + edges: marketsWithSuccessorID, }, }, }, }; - const successorMarketsMock: MockedResponse = { - request: { - query: SuccessorMarketIdsDocument, - }, - result: { - data: { - marketsConnection: { - __typename: 'MarketConnection', - edges: [ - { - node: { - id: 'include-0', - successorMarketID: 'successorMarketID', - parentMarketID: '', - }, - }, - ], - }, - }, - }, - }; - await act(() => { + + await act(async () => { render( { ); }); - await waitFor(() => { - expect( - screen.getByRole('button', { name: /^SuccessorCode/ }) - ).toBeInTheDocument(); - }); - expect( - screen.getByRole('columnheader', { - name: (_name, element) => - element.getAttribute('col-id') === 'successorMarket', - }) - ).toBeInTheDocument(); - screen - .getAllByRole('gridcell', { - name: (_name, element) => - element.getAttribute('col-id') === 'successorMarket', - }) - .forEach((element) => { - expect(element.querySelector('[title="Future"]')?.textContent).toEqual( - 'Futr' - ); - }); - }); + const container = within( + document.querySelector('.ag-center-cols-container') as HTMLElement + ); + const cell = container.getAllByRole('gridcell', { + name: (_name, element) => element.getAttribute('col-id') === 'code', + })[0]; - it('feature flag should hide successors', async () => { - const mockedFlags = jest.mocked(FLAGS); - mockedFlags.SUCCESSOR_MARKETS = false; - - const mixedMarkets = [ - { - __typename: 'MarketEdge' as const, - node: createMarketFragment({ - id: 'include-0', - state: MarketState.STATE_SETTLED, - }), - }, - { - __typename: 'MarketEdge' as const, - node: { - ...createMarketFragment({ - id: 'successorMarketID', - state: MarketState.STATE_ACTIVE, - }), - tradableInstrument: { - ...createMarketFragment().tradableInstrument, - instrument: { - ...createMarketFragment().tradableInstrument.instrument, - id: 'successorAssset', - name: 'Successor Market Name', - code: 'SuccessorCode', - }, - }, - }, - }, - ]; - const mixedMarketsMock: MockedResponse = { - request: { - query: MarketsDocument, - }, - result: { - data: { - marketsConnection: { - __typename: 'MarketConnection', - edges: mixedMarkets, - }, - }, - }, - }; - const successorMarketsMock: MockedResponse = { - request: { - query: SuccessorMarketIdsDocument, - }, - result: { - data: { - marketsConnection: { - __typename: 'MarketConnection', - edges: [ - { - node: { - id: 'include-0', - successorMarketID: 'successorMarketID', - parentMarketID: '', - }, - }, - ], - }, - }, - }, - }; - render( - - - - - - - + expect(within(cell).getByTestId('stack-cell-secondary')).toHaveTextContent( + 'PRNT' ); - await waitFor(() => { - expect( - screen.getByRole('columnheader', { - name: (_name, element) => - element.getAttribute('col-id') === 'settlementDate', - }) - ).toBeInTheDocument(); - }); - screen.getAllByRole('columnheader').forEach((element) => { - expect(element.getAttribute('col-id')).not.toEqual('successorMarket'); - }); }); }); diff --git a/apps/trading/client-pages/markets/closed.tsx b/apps/trading/client-pages/markets/closed.tsx index cc5b2267c..152585663 100644 --- a/apps/trading/client-pages/markets/closed.tsx +++ b/apps/trading/client-pages/markets/closed.tsx @@ -4,13 +4,10 @@ import type { VegaICellRendererParams, VegaValueFormatterParams, } from '@vegaprotocol/datagrid'; -import { - AgGridLazy as AgGrid, - COL_DEFS, - MarketNameCell, -} from '@vegaprotocol/datagrid'; +import { AgGridLazy as AgGrid, COL_DEFS } from '@vegaprotocol/datagrid'; import { useMemo } from 'react'; import { t } from '@vegaprotocol/i18n'; +import type { ProductType } from '@vegaprotocol/types'; import { MarketState, MarketStateMapping } from '@vegaprotocol/types'; import { addDecimalsFormatNumber, @@ -20,17 +17,13 @@ import type { DataSourceFilterFragment, MarketMaybeWithData, } from '@vegaprotocol/markets'; -import { - MarketActionsDropdown, - closedMarketsWithDataProvider, -} from '@vegaprotocol/markets'; +import { closedMarketsWithDataProvider } from '@vegaprotocol/markets'; import { useAssetDetailsDialogStore } from '@vegaprotocol/assets'; -import type { ColDef } from 'ag-grid-community'; -import { FLAGS } from '@vegaprotocol/environment'; import { SettlementDateCell } from './settlement-date-cell'; import { SettlementPriceCell } from './settlement-price-cell'; import { useDataProvider } from '@vegaprotocol/data-provider'; -import { SuccessorMarketRenderer } from './successor-market-cell'; +import { MarketActionsDropdown } from './market-table-actions'; +import { MarketCodeCell } from './market-code-cell'; type SettlementAsset = MarketMaybeWithData['tradableInstrument']['instrument']['product']['settlementAsset']; @@ -51,7 +44,9 @@ interface Row { setlementDataSourceFilter: DataSourceFilterFragment | undefined; tradingTerminationOracleId: string; settlementAsset: SettlementAsset; - productType: string; + productType: ProductType | undefined; + successorMarketID: string | null | undefined; + parentMarketID: string | null | undefined; } export const Closed = () => { @@ -95,16 +90,19 @@ export const Closed = () => { tradingTerminationOracleId: instrument.product.dataSourceSpecForTradingTermination.id, settlementAsset: instrument.product.settlementAsset, - productType: instrument.product.__typename || '', + productType: instrument.product.__typename, + successorMarketID: market.successorMarketID, + parentMarketID: market.parentMarketID, }; return row; }); - return ( -
- -
- ); + + return ; +}; + +const components = { + MarketCodeCell, }; const ClosedMarketsDataGrid = ({ @@ -117,15 +115,11 @@ const ClosedMarketsDataGrid = ({ const openAssetDialog = useAssetDetailsDialogStore((store) => store.open); const colDefs = useMemo(() => { - const cols: ColDef[] = compact([ + return [ { headerName: t('Market'), field: 'code', - cellRenderer: 'MarketNameCell', - }, - { - headerName: t('Description'), - field: 'name', + cellRenderer: 'MarketCodeCell', }, { headerName: t('Status'), @@ -176,12 +170,6 @@ const ClosedMarketsDataGrid = ({ }, }, }, - FLAGS.SUCCESSOR_MARKETS && { - headerName: t('Successor market'), - field: 'id', - colId: 'successorMarket', - cellRenderer: 'SuccessorMarketRenderer', - }, { headerName: t('Best bid'), field: 'bestBidPrice', @@ -263,12 +251,13 @@ const ClosedMarketsDataGrid = ({ ); }, }, - ]); - return cols; + ]; }, [openAssetDialog]); return ( @@ -276,8 +265,8 @@ const ClosedMarketsDataGrid = ({ rowData={rowData} columnDefs={colDefs} getRowId={({ data }) => data.id} - components={{ SuccessorMarketRenderer, MarketNameCell }} overlayNoRowsTemplate={error ? error.message : t('No markets')} + components={components} /> ); }; diff --git a/apps/trading/client-pages/markets/market-code-cell.spec.tsx b/apps/trading/client-pages/markets/market-code-cell.spec.tsx new file mode 100644 index 000000000..5570aae86 --- /dev/null +++ b/apps/trading/client-pages/markets/market-code-cell.spec.tsx @@ -0,0 +1,82 @@ +import { render, screen } from '@testing-library/react'; +import { ProductTypeShortName } from '@vegaprotocol/types'; +import type { MarketCodeCellProps } from './market-code-cell'; +import { MarketCodeCell } from './market-code-cell'; + +describe('MarketCodeCell', () => { + const renderComponent = (props: MarketCodeCellProps) => { + return render(); + }; + + it('renders SCCR if the market is a successor', () => { + const productType = 'Future'; + const code = 'code'; + const props = { + value: 'code', + data: { + productType, + parentMarketID: 'foo', + successorMarketID: undefined, + }, + } as const; + renderComponent(props); + expect(screen.getByTestId('stack-cell-primary')).toHaveTextContent(code); + expect(screen.getByTestId('stack-cell-secondary')).toHaveTextContent( + ProductTypeShortName[productType] + ); + expect(screen.getByTestId('stack-cell-secondary')).toHaveTextContent( + 'SCCR' + ); + expect(screen.getByTestId('stack-cell-secondary')).not.toHaveTextContent( + 'PRNT' + ); + }); + + it('renders PRNT if the market is a parent', () => { + const productType = 'Future'; + const code = 'code'; + const props = { + value: 'code', + data: { + productType, + parentMarketID: undefined, + successorMarketID: 'foo', + }, + } as const; + renderComponent(props); + expect(screen.getByTestId('stack-cell-primary')).toHaveTextContent(code); + expect(screen.getByTestId('stack-cell-secondary')).toHaveTextContent( + ProductTypeShortName[productType] + ); + expect(screen.getByTestId('stack-cell-secondary')).toHaveTextContent( + 'PRNT' + ); + expect(screen.getByTestId('stack-cell-secondary')).not.toHaveTextContent( + 'SCCR' + ); + }); + + it('renders both SCCR and PRNT if the market is both a parent and a successor', () => { + const productType = 'Future'; + const code = 'code'; + const props = { + value: 'code', + data: { + productType, + parentMarketID: 'foo', + successorMarketID: 'bar', + }, + } as const; + renderComponent(props); + expect(screen.getByTestId('stack-cell-primary')).toHaveTextContent(code); + expect(screen.getByTestId('stack-cell-secondary')).toHaveTextContent( + ProductTypeShortName[productType] + ); + expect(screen.getByTestId('stack-cell-secondary')).toHaveTextContent( + 'PRNT' + ); + expect(screen.getByTestId('stack-cell-secondary')).toHaveTextContent( + 'SCCR' + ); + }); +}); diff --git a/apps/trading/client-pages/markets/market-code-cell.tsx b/apps/trading/client-pages/markets/market-code-cell.tsx new file mode 100644 index 000000000..68c68e988 --- /dev/null +++ b/apps/trading/client-pages/markets/market-code-cell.tsx @@ -0,0 +1,51 @@ +import compact from 'lodash/compact'; +import type { ProductType } from '@vegaprotocol/types'; +import { ProductTypeMapping, ProductTypeShortName } from '@vegaprotocol/types'; +import { StackedCell } from '@vegaprotocol/datagrid'; +import { t } from '@vegaprotocol/i18n'; + +export interface MarketCodeCellProps { + value: string | undefined; // market code + data: { + productType: ProductType | undefined; + parentMarketID: string | null | undefined; + successorMarketID: string | null | undefined; + }; +} + +export const MarketCodeCell = ({ value, data }: MarketCodeCellProps) => { + if (!value || !data || !data.productType) return null; + + const infoSpanClasses = + 'mr-1 pr-1 uppercase border-r last:pr-0 last:mr-0 last:border-r-0 border-vega-clight-200 dark:border-vega-cdark-200'; + + const info = compact([ + + {ProductTypeShortName[data.productType]} + , + data.parentMarketID && ( + + {t('SCCR')} + + ), + data.successorMarketID && ( + + {t('PRNT')} + + ), + ]); + + return ; +}; diff --git a/apps/trading/client-pages/markets/market-list-table.tsx b/apps/trading/client-pages/markets/market-list-table.tsx new file mode 100644 index 000000000..8ead66f63 --- /dev/null +++ b/apps/trading/client-pages/markets/market-list-table.tsx @@ -0,0 +1,35 @@ +import type { TypedDataAgGrid } from '@vegaprotocol/datagrid'; +import { AgGridLazy as AgGrid, PriceFlashCell } from '@vegaprotocol/datagrid'; +import type { MarketMaybeWithData } from '@vegaprotocol/markets'; +import { useColumnDefs } from './use-column-defs'; + +export const getRowId = ({ data }: { data: { id: string } }) => data.id; + +const defaultColDef = { + sortable: true, + filter: true, + filterParams: { buttons: ['reset'] }, +}; + +const components = { + PriceFlashCell, +}; + +type Props = TypedDataAgGrid; + +export const MarketListTable = (props: Props) => { + const columnDefs = useColumnDefs(); + + return ( + + ); +}; + +export default MarketListTable; diff --git a/libs/markets/src/lib/components/markets-container/market-table-actions.tsx b/apps/trading/client-pages/markets/market-table-actions.tsx similarity index 60% rename from libs/markets/src/lib/components/markets-container/market-table-actions.tsx rename to apps/trading/client-pages/markets/market-table-actions.tsx index 21c8df2da..01db1d70f 100644 --- a/libs/markets/src/lib/components/markets-container/market-table-actions.tsx +++ b/apps/trading/client-pages/markets/market-table-actions.tsx @@ -9,14 +9,21 @@ import { } from '@vegaprotocol/ui-toolkit'; import { DApp, EXPLORER_MARKET, useLinks } from '@vegaprotocol/environment'; import { useAssetDetailsDialogStore } from '@vegaprotocol/assets'; +import { useNavigate } from 'react-router-dom'; +import { Links, Routes } from '../../pages/client-router'; export const MarketActionsDropdown = ({ marketId, assetId, + successorMarketID, + parentMarketID, }: { marketId: string; assetId: string; + successorMarketID: string | null | undefined; + parentMarketID: string | null | undefined; }) => { + const navigate = useNavigate(); const open = useAssetDetailsDialogStore((store) => store.open); const linkCreator = useLinks(DApp.Explorer); @@ -42,6 +49,26 @@ export const MarketActionsDropdown = ({ {t('View settlement asset details')} + {parentMarketID && ( + { + navigate(Links[Routes.MARKET](parentMarketID)); + }} + > + + {t('View parent market')} + + )} + {successorMarketID && ( + { + navigate(Links[Routes.MARKET](successorMarketID)); + }} + > + + {t('View successor market')} + + )} ); }; diff --git a/apps/trading/client-pages/markets/markets-page.tsx b/apps/trading/client-pages/markets/markets-page.tsx index e318222c5..b32bd0a0f 100644 --- a/apps/trading/client-pages/markets/markets-page.tsx +++ b/apps/trading/client-pages/markets/markets-page.tsx @@ -6,7 +6,7 @@ import { Tab, TradingAnchorButton, } from '@vegaprotocol/ui-toolkit'; -import { Markets } from './markets'; +import { OpenMarkets } from './open-markets'; import { Proposed } from './proposed'; import { usePageTitleStore } from '../../stores'; import { Closed } from './closed'; @@ -33,7 +33,7 @@ export const MarketsPage = () => {
- + { - const handleOnSelect = useMarketClickHandler(); - return ( - - ); -}; diff --git a/apps/trading/client-pages/markets/open-markets.tsx b/apps/trading/client-pages/markets/open-markets.tsx new file mode 100644 index 000000000..ee8a20473 --- /dev/null +++ b/apps/trading/client-pages/markets/open-markets.tsx @@ -0,0 +1,63 @@ +import { useDataProvider } from '@vegaprotocol/data-provider'; +import type { MarketMaybeWithData } from '@vegaprotocol/markets'; +import { marketListProvider } from '@vegaprotocol/markets'; +import { useEffect } from 'react'; +import { t } from '@vegaprotocol/i18n'; +import type { CellClickedEvent } from 'ag-grid-community'; +import MarketListTable from './market-list-table'; +import { useMarketClickHandler } from '../../lib/hooks/use-market-click-handler'; +import { Interval } from '@vegaprotocol/types'; +import { useYesterday } from '@vegaprotocol/react-helpers'; + +const POLLING_TIME = 2000; + +export const OpenMarkets = () => { + const handleOnSelect = useMarketClickHandler(); + const yesterday = useYesterday(); + const { data, error, reload } = useDataProvider({ + dataProvider: marketListProvider, + variables: { + since: new Date(yesterday).toISOString(), + interval: Interval.INTERVAL_I1H, + }, + }); + + useEffect(() => { + const interval = setInterval(() => { + reload(); + }, POLLING_TIME); + return () => { + clearInterval(interval); + }; + }, [reload]); + + return ( + ) => { + if (!data) return; + + // prevent navigating to the market page if any of the below cells are clicked + // event.preventDefault or event.stopPropagation dont seem to apply for aggird + const colId = column.getColId(); + + if ( + [ + 'tradableInstrument.instrument.product.settlementAsset.symbol', + 'market-actions', + ].includes(colId) + ) { + return; + } + + // @ts-ignore metaKey exists + handleOnSelect(data.id, event ? event.metaKey : false); + }} + overlayNoRowsTemplate={error ? error.message : t('No markets')} + /> + ); +}; diff --git a/apps/trading/client-pages/markets/oracle-status.tsx b/apps/trading/client-pages/markets/oracle-status.tsx new file mode 100644 index 000000000..4e4f2f984 --- /dev/null +++ b/apps/trading/client-pages/markets/oracle-status.tsx @@ -0,0 +1,46 @@ +import { useEnvironment } from '@vegaprotocol/environment'; +import { Icon } from '@vegaprotocol/ui-toolkit'; +import type { IconName } from '@blueprintjs/icons'; +import type { Market } from '@vegaprotocol/markets'; +import { + getMatchingOracleProvider, + getVerifiedStatusIcon, + useOracleProofs, +} from '@vegaprotocol/markets'; + +export const OracleStatus = ({ + dataSourceSpecForSettlementData, + dataSourceSpecForTradingTermination, +}: Pick< + Market['tradableInstrument']['instrument']['product'], + 'dataSourceSpecForSettlementData' | 'dataSourceSpecForTradingTermination' +>) => { + const { ORACLE_PROOFS_URL } = useEnvironment(); + const { data: providers } = useOracleProofs(ORACLE_PROOFS_URL); + + if (providers) { + const settlementDataProvider = getMatchingOracleProvider( + dataSourceSpecForSettlementData.data, + providers + ); + const tradingTerminationDataProvider = getMatchingOracleProvider( + dataSourceSpecForTradingTermination.data, + providers + ); + let maliciousOracleProvider = null; + + if (settlementDataProvider?.oracle.status !== 'GOOD') { + maliciousOracleProvider = settlementDataProvider; + } else if (tradingTerminationDataProvider?.oracle.status !== 'GOOD') { + maliciousOracleProvider = tradingTerminationDataProvider; + } + + if (!maliciousOracleProvider) return null; + + const { icon } = getVerifiedStatusIcon(maliciousOracleProvider); + + return ; + } + + return null; +}; diff --git a/apps/trading/client-pages/markets/parent-market-cell.tsx b/apps/trading/client-pages/markets/parent-market-cell.tsx new file mode 100644 index 000000000..b5a4bb2fe --- /dev/null +++ b/apps/trading/client-pages/markets/parent-market-cell.tsx @@ -0,0 +1,15 @@ +import { useMarketsMapProvider } from '@vegaprotocol/markets'; + +export const ParentMarketCell = ({ + value, +}: { + value: string; // parentMarketId +}) => { + const { data, loading } = useMarketsMapProvider(); + + if (loading) return null; + + if (!data || !data[value]) return -; + + return
{data[value].tradableInstrument.instrument.code}
; +}; diff --git a/apps/trading/client-pages/markets/proposed.tsx b/apps/trading/client-pages/markets/proposed.tsx index 67a20cbc9..0cf9175c1 100644 --- a/apps/trading/client-pages/markets/proposed.tsx +++ b/apps/trading/client-pages/markets/proposed.tsx @@ -1,6 +1,10 @@ import { ProposalsList } from '@vegaprotocol/proposals'; -import { SuccessorMarketRenderer } from './successor-market-cell'; +import { ParentMarketCell } from './parent-market-cell'; + +const cellRenderers = { + ParentMarketCell, +}; export const Proposed = () => { - return ; + return ; }; diff --git a/apps/trading/client-pages/markets/successor-market-cell.spec.tsx b/apps/trading/client-pages/markets/successor-market-cell.spec.tsx deleted file mode 100644 index f91997194..000000000 --- a/apps/trading/client-pages/markets/successor-market-cell.spec.tsx +++ /dev/null @@ -1,190 +0,0 @@ -import { render, screen, act, waitFor } from '@testing-library/react'; -import { MockedProvider } from '@apollo/client/testing'; -import userEvent from '@testing-library/user-event'; -import type { Market } from '@vegaprotocol/markets'; -import { SuccessorMarketRenderer } from './successor-market-cell'; -import { - MarketsDocument, - SuccessorMarketIdsDocument, -} from '@vegaprotocol/markets'; -import { createMarketFragment } from '@vegaprotocol/mock'; - -const mockSuccessorsQuery = [ - { - id: 'market1', - parentMarketID: 'parentMarket1', - successorMarketID: 'successorMarket1', - }, - { id: 'market2', parentMarketID: 'parentMarket2' }, - { id: 'market3', successorMarketID: 'successorMarket3' }, -]; -const parentMarket1 = { - id: 'parentMarket1', - tradableInstrument: { - instrument: { code: 'code parent 1', id: '1' }, - }, -} as unknown as Market; -const successorMarket1 = { - id: 'successorMarket1', - tradableInstrument: { - instrument: { code: 'code successor 1', id: '2' }, - }, -} as unknown as Market; -const parentMarket2 = { - id: 'parentMarket2', - tradableInstrument: { - instrument: { code: 'code parent 2', id: '3' }, - }, -} as unknown as Market; -const successorMarket3 = { - id: 'successorMarket3', - tradableInstrument: { - instrument: { code: 'code successor 3', id: '4' }, - }, -} as unknown as Market; - -const mockMarkets = [ - parentMarket1, - successorMarket1, - parentMarket2, - successorMarket3, -]; - -const mockClickHandler = jest.fn(); -jest.mock('../../lib/hooks/use-market-click-handler', () => ({ - useMarketClickHandler: jest.fn().mockImplementation(() => mockClickHandler), -})); - -const marketMock = { - request: { - query: MarketsDocument, - variables: undefined, - }, - result: { - data: { - marketsConnection: { - edges: mockMarkets.map((item) => ({ - node: { - ...createMarketFragment(item), - }, - })), - }, - }, - }, -}; - -const successorMock = { - request: { - query: SuccessorMarketIdsDocument, - }, - result: { - data: { - marketsConnection: { - edges: mockSuccessorsQuery.map((item) => ({ - node: { - ...item, - }, - })), - }, - }, - }, -}; - -const mocks = [marketMock, successorMock]; - -describe('SuccessorMarketRenderer', () => { - beforeEach(() => { - jest.clearAllMocks(); - }); - it('should properly rendered successor market', async () => { - const successorValue = 'market1'; - render( - - - - ); - await waitFor(() => { - expect(screen.getByTestId('market-code')).toBeInTheDocument(); - }); - expect(screen.getByText('code successor 1')).toBeInTheDocument(); - expect(screen.getByText('Futr')).toBeInTheDocument(); - - await userEvent.click(screen.getByRole('button')); - await waitFor(() => { - expect(mockClickHandler).toHaveBeenCalledWith('successorMarket1', false); - }); - }); - it('should properly rendered parent market', async () => { - const successorValue = 'market1'; - render( - - - - ); - await waitFor(() => { - expect(screen.getByTestId('market-code')).toBeInTheDocument(); - }); - expect(screen.getByText('code parent 1')).toBeInTheDocument(); - expect(screen.getByText('Futr')).toBeInTheDocument(); - - await userEvent.click(screen.getByRole('button')); - - await waitFor(() => { - expect(mockClickHandler).toHaveBeenCalledWith('parentMarket1', false); - }); - }); - it('should properly rendered only parent market', async () => { - const successorValue = 'market2'; - const { rerender } = render( - - - - ); - await waitFor(() => { - expect(screen.getByTestId('market-code')).toBeInTheDocument(); - }); - expect(screen.getByText('code parent 2')).toBeInTheDocument(); - expect(screen.getByText('Futr')).toBeInTheDocument(); - await userEvent.click(screen.getByRole('button')); - - await waitFor(() => { - expect(mockClickHandler).toHaveBeenCalledWith('parentMarket2', false); - }); - - rerender( - - - - ); - - expect(screen.getByText('-')).toBeInTheDocument(); - }); - it('should properly rendered only successor market', async () => { - const successorValue = 'market3'; - const { rerender } = render( - - - - ); - await waitFor(() => { - expect(screen.getByTestId('market-code')).toBeInTheDocument(); - }); - expect(screen.getByText('code successor 3')).toBeInTheDocument(); - expect(screen.getByText('Futr')).toBeInTheDocument(); - - await userEvent.click(screen.getByRole('button')); - - await waitFor(() => { - expect(mockClickHandler).toHaveBeenCalledWith('successorMarket3', false); - }); - - await act(() => { - rerender( - - - - ); - }); - expect(screen.getByText('-')).toBeInTheDocument(); - }); -}); diff --git a/apps/trading/client-pages/markets/successor-market-cell.tsx b/apps/trading/client-pages/markets/successor-market-cell.tsx deleted file mode 100644 index da8bb4677..000000000 --- a/apps/trading/client-pages/markets/successor-market-cell.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import React from 'react'; -import { MarketNameCell } from '@vegaprotocol/datagrid'; -import { useDataProvider } from '@vegaprotocol/data-provider'; -import { marketProvider, useSuccessorMarketIds } from '@vegaprotocol/markets'; -import { useMarketClickHandler } from '../../lib/hooks/use-market-click-handler'; - -export const SuccessorMarketRenderer = ({ - value, - parent, -}: { - value: string; - parent?: boolean; -}) => { - const successors = useSuccessorMarketIds(value); - const onMarketClick = useMarketClickHandler(); - - const lookupValue = successors - ? parent - ? successors.parentMarketID - : successors.successorMarketID - : ''; - - const { data } = useDataProvider({ - dataProvider: marketProvider, - variables: { - marketId: lookupValue || '', - }, - skip: !lookupValue, - }); - - return data ? ( - - ) : ( - '-' - ); -}; diff --git a/apps/trading/client-pages/markets/use-column-defs.tsx b/apps/trading/client-pages/markets/use-column-defs.tsx new file mode 100644 index 000000000..6f9156c9f --- /dev/null +++ b/apps/trading/client-pages/markets/use-column-defs.tsx @@ -0,0 +1,226 @@ +import { useMemo } from 'react'; +import type { ColDef, ValueFormatterParams } from 'ag-grid-community'; +import { t } from '@vegaprotocol/i18n'; +import type { + VegaICellRendererParams, + VegaValueFormatterParams, + VegaValueGetterParams, +} from '@vegaprotocol/datagrid'; +import { COL_DEFS, SetFilter } from '@vegaprotocol/datagrid'; +import * as Schema from '@vegaprotocol/types'; +import { addDecimalsFormatNumber, toBigNum } from '@vegaprotocol/utils'; +import { ButtonLink, Tooltip } from '@vegaprotocol/ui-toolkit'; +import { useAssetDetailsDialogStore } from '@vegaprotocol/assets'; +import type { + MarketMaybeWithData, + MarketMaybeWithDataAndCandles, +} from '@vegaprotocol/markets'; +import { MarketActionsDropdown } from './market-table-actions'; +import { calcCandleVolume } from '@vegaprotocol/markets'; +import { MarketCodeCell } from './market-code-cell'; + +const { MarketTradingMode, AuctionTrigger } = Schema; + +export const useColumnDefs = () => { + const { open: openAssetDetailsDialog } = useAssetDetailsDialogStore(); + return useMemo( + () => [ + { + headerName: t('Market'), + field: 'tradableInstrument.instrument.code', + flex: 2, + cellRenderer: ({ + value, + data, + }: VegaICellRendererParams< + MarketMaybeWithData, + 'tradableInstrument.instrument.code' + >) => ( + + ), + }, + { + headerName: t('Description'), + field: 'tradableInstrument.instrument.name', + flex: 2, + }, + { + headerName: t('Trading mode'), + field: 'tradingMode', + cellRenderer: ({ + data, + }: VegaICellRendererParams) => { + if (!data?.data) return '-'; + const { trigger, marketTradingMode } = data.data; + + const withTriggerInfo = + marketTradingMode === + MarketTradingMode.TRADING_MODE_MONITORING_AUCTION && + trigger && + trigger !== AuctionTrigger.AUCTION_TRIGGER_UNSPECIFIED; + + if (withTriggerInfo) { + return ( + + + {Schema.MarketTradingModeMapping[marketTradingMode]} + + + ); + } + + return Schema.MarketTradingModeMapping[marketTradingMode]; + }, + filter: SetFilter, + filterParams: { + set: Schema.MarketTradingModeMapping, + }, + }, + { + headerName: t('Status'), + field: 'state', + valueFormatter: ({ + data, + }: VegaValueFormatterParams) => { + return data?.state ? Schema.MarketStateMapping[data.state] : '-'; + }, + filter: SetFilter, + filterParams: { + set: Schema.MarketStateMapping, + }, + }, + { + headerName: t('Mark price'), + field: 'data.markPrice', + type: 'rightAligned', + cellRenderer: 'PriceFlashCell', + filter: 'agNumberColumnFilter', + valueGetter: ({ data }: VegaValueGetterParams) => { + return data?.data?.markPrice === undefined + ? undefined + : toBigNum(data?.data?.markPrice, data.decimalPlaces).toNumber(); + }, + valueFormatter: ({ + data, + }: VegaValueFormatterParams) => + data?.data?.bestOfferPrice === undefined + ? '-' + : addDecimalsFormatNumber(data.data.markPrice, data.decimalPlaces), + }, + { + headerName: t('24h volume'), + type: 'rightAligned', + field: 'data.candles', + valueGetter: ({ + data, + }: VegaValueGetterParams) => { + if (!data) return 0; + const candles = data?.candles; + const vol = candles ? calcCandleVolume(candles) : '0'; + return Number(vol); + }, + valueFormatter: ({ + data, + }: ValueFormatterParams) => { + const candles = data?.candles; + const vol = candles ? calcCandleVolume(candles) : '0'; + const volume = + data && vol && vol !== '0' + ? addDecimalsFormatNumber(vol, data.positionDecimalPlaces) + : '0.00'; + return volume; + }, + }, + { + headerName: t('Settlement asset'), + field: 'tradableInstrument.instrument.product.settlementAsset.symbol', + cellRenderer: ({ + data, + }: VegaICellRendererParams< + MarketMaybeWithData, + 'tradableInstrument.instrument.product.settlementAsset.symbol' + >) => { + const value = + data?.tradableInstrument.instrument.product.settlementAsset; + return value ? ( + { + openAssetDetailsDialog(value.id, e.target as HTMLElement); + }} + > + {value.symbol} + + ) : ( + '' + ); + }, + }, + { + headerName: t('Spread'), + field: 'data.bestBidPrice', + type: 'rightAligned', + filter: 'agNumberColumnFilter', + cellRenderer: 'PriceFlashCell', + valueGetter: ({ data }: VegaValueGetterParams) => { + if (!data || !data.data?.bestOfferPrice || !data.data?.bestBidPrice) { + return undefined; + } + + const offer = toBigNum(data.data.bestOfferPrice, data.decimalPlaces); + const bid = toBigNum(data.data.bestBidPrice, data.decimalPlaces); + + const spread = offer.minus(bid).toNumber(); + + // The calculation above can result in '-0' being rendered after formatting + // so return Math.abs to remove it and just render '0' + if (spread === 0) { + return Math.abs(spread); + } + + return spread; + }, + valueFormatter: ({ + value, + }: VegaValueFormatterParams< + MarketMaybeWithData, + 'data.bestBidPrice' + >) => { + if (!value) return '-'; + return value.toString(); + }, + }, + { + colId: 'market-actions', + field: 'id', + ...COL_DEFS.actions, + cellRenderer: ({ + data, + }: VegaICellRendererParams) => { + if (!data) return null; + return ( + + ); + }, + }, + ], + [openAssetDetailsDialog] + ); +}; diff --git a/apps/trading/lib/hooks/use-market-click-handler.ts b/apps/trading/lib/hooks/use-market-click-handler.ts index 15db3617e..2fef70d08 100644 --- a/apps/trading/lib/hooks/use-market-click-handler.ts +++ b/apps/trading/lib/hooks/use-market-click-handler.ts @@ -1,24 +1,18 @@ -import { useNavigate, useParams, useLocation } from 'react-router-dom'; +import { useNavigate } from 'react-router-dom'; import { useCallback } from 'react'; import { Links, Routes } from '../../pages/client-router'; export const useMarketClickHandler = (replace = false) => { const navigate = useNavigate(); - const { marketId } = useParams(); - const { pathname } = useLocation(); - const isMarketPage = pathname.match(/^\/markets\/(.+)/); - return useCallback( - (selectedId: string, metaKey?: boolean) => { - const link = Links[Routes.MARKET](selectedId); - if (metaKey) { - window.open(`/#${link}`, '_blank'); - } else if (selectedId !== marketId || !isMarketPage) { - navigate(link, { replace }); - } - }, - [navigate, marketId, replace, isMarketPage] - ); + return (selectedId: string, metaKey?: boolean) => { + const link = Links[Routes.MARKET](selectedId); + if (metaKey) { + window.open(`/#${link}`, '_blank'); + } else { + navigate(link, { replace }); + } + }; }; export const useMarketLiquidityClickHandler = () => { diff --git a/libs/datagrid/src/index.ts b/libs/datagrid/src/index.ts index 76938986b..b166a9b7c 100644 --- a/libs/datagrid/src/index.ts +++ b/libs/datagrid/src/index.ts @@ -12,6 +12,7 @@ export * from './lib/cells/centered-grid-cell'; export * from './lib/cells/market-name-cell'; export * from './lib/cells/order-type-cell'; export * from './lib/cells/size'; +export * from './lib/cells/stacked-cell'; export * from './lib/filters/date-range-filter'; export * from './lib/filters/set-filter'; diff --git a/libs/positions/src/lib/stacked-cell.tsx b/libs/datagrid/src/lib/cells/stacked-cell.tsx similarity index 100% rename from libs/positions/src/lib/stacked-cell.tsx rename to libs/datagrid/src/lib/cells/stacked-cell.tsx diff --git a/libs/markets/src/lib/__generated__/markets.ts b/libs/markets/src/lib/__generated__/markets.ts index addf669a7..9a3feea33 100644 --- a/libs/markets/src/lib/__generated__/markets.ts +++ b/libs/markets/src/lib/__generated__/markets.ts @@ -7,12 +7,12 @@ export type DataSourceFilterFragment = { __typename?: 'Filter', key: { __typenam export type DataSourceSpecFragment = { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType, numberDecimalPlaces?: number | null } }> | null } } | { __typename?: 'DataSourceDefinitionInternal' } }; -export type MarketFieldsFragment = { __typename?: 'Market', id: string, decimalPlaces: number, positionDecimalPlaces: number, state: Types.MarketState, tradingMode: Types.MarketTradingMode, fees: { __typename?: 'Fees', factors: { __typename?: 'FeeFactors', makerFee: string, infrastructureFee: string, liquidityFee: string } }, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', id: string, name: string, code: string, metadata: { __typename?: 'InstrumentMetadata', tags?: Array | null }, product: { __typename?: 'Future', quoteName: string, settlementAsset: { __typename?: 'Asset', id: string, symbol: string, name: string, decimals: number, quantum: string }, dataSourceSpecForTradingTermination: { __typename?: 'DataSourceSpec', id: string, 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, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType, numberDecimalPlaces?: number | null } }> | null } } | { __typename?: 'DataSourceDefinitionInternal' } } }, dataSourceSpecForSettlementData: { __typename?: 'DataSourceSpec', id: string, 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, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType, numberDecimalPlaces?: number | null } }> | null } } | { __typename?: 'DataSourceDefinitionInternal' } } }, dataSourceSpecBinding: { __typename?: 'DataSourceSpecToFutureBinding', settlementDataProperty: string, tradingTerminationProperty: string } } } }, marketTimestamps: { __typename?: 'MarketTimestamps', open: any, close: any } }; +export type MarketFieldsFragment = { __typename?: 'Market', id: string, decimalPlaces: number, positionDecimalPlaces: number, state: Types.MarketState, tradingMode: Types.MarketTradingMode, parentMarketID?: string | null, successorMarketID?: string | null, fees: { __typename?: 'Fees', factors: { __typename?: 'FeeFactors', makerFee: string, infrastructureFee: string, liquidityFee: string } }, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', id: string, name: string, code: string, metadata: { __typename?: 'InstrumentMetadata', tags?: Array | null }, product: { __typename?: 'Future', quoteName: string, settlementAsset: { __typename?: 'Asset', id: string, symbol: string, name: string, decimals: number, quantum: string }, dataSourceSpecForTradingTermination: { __typename?: 'DataSourceSpec', id: string, 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, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType, numberDecimalPlaces?: number | null } }> | null } } | { __typename?: 'DataSourceDefinitionInternal' } } }, dataSourceSpecForSettlementData: { __typename?: 'DataSourceSpec', id: string, 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, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType, numberDecimalPlaces?: number | null } }> | null } } | { __typename?: 'DataSourceDefinitionInternal' } } }, dataSourceSpecBinding: { __typename?: 'DataSourceSpecToFutureBinding', settlementDataProperty: string, tradingTerminationProperty: string } } } }, marketTimestamps: { __typename?: 'MarketTimestamps', open: any, close: any } }; export type MarketsQueryVariables = Types.Exact<{ [key: string]: never; }>; -export type MarketsQuery = { __typename?: 'Query', marketsConnection?: { __typename?: 'MarketConnection', edges: Array<{ __typename?: 'MarketEdge', node: { __typename?: 'Market', id: string, decimalPlaces: number, positionDecimalPlaces: number, state: Types.MarketState, tradingMode: Types.MarketTradingMode, fees: { __typename?: 'Fees', factors: { __typename?: 'FeeFactors', makerFee: string, infrastructureFee: string, liquidityFee: string } }, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', id: string, name: string, code: string, metadata: { __typename?: 'InstrumentMetadata', tags?: Array | null }, product: { __typename?: 'Future', quoteName: string, settlementAsset: { __typename?: 'Asset', id: string, symbol: string, name: string, decimals: number, quantum: string }, dataSourceSpecForTradingTermination: { __typename?: 'DataSourceSpec', id: string, 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, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType, numberDecimalPlaces?: number | null } }> | null } } | { __typename?: 'DataSourceDefinitionInternal' } } }, dataSourceSpecForSettlementData: { __typename?: 'DataSourceSpec', id: string, 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, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType, numberDecimalPlaces?: number | null } }> | null } } | { __typename?: 'DataSourceDefinitionInternal' } } }, dataSourceSpecBinding: { __typename?: 'DataSourceSpecToFutureBinding', settlementDataProperty: string, tradingTerminationProperty: string } } } }, marketTimestamps: { __typename?: 'MarketTimestamps', open: any, close: any } } }> } | null }; +export type MarketsQuery = { __typename?: 'Query', marketsConnection?: { __typename?: 'MarketConnection', edges: Array<{ __typename?: 'MarketEdge', node: { __typename?: 'Market', id: string, decimalPlaces: number, positionDecimalPlaces: number, state: Types.MarketState, tradingMode: Types.MarketTradingMode, parentMarketID?: string | null, successorMarketID?: string | null, fees: { __typename?: 'Fees', factors: { __typename?: 'FeeFactors', makerFee: string, infrastructureFee: string, liquidityFee: string } }, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', id: string, name: string, code: string, metadata: { __typename?: 'InstrumentMetadata', tags?: Array | null }, product: { __typename?: 'Future', quoteName: string, settlementAsset: { __typename?: 'Asset', id: string, symbol: string, name: string, decimals: number, quantum: string }, dataSourceSpecForTradingTermination: { __typename?: 'DataSourceSpec', id: string, 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, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType, numberDecimalPlaces?: number | null } }> | null } } | { __typename?: 'DataSourceDefinitionInternal' } } }, dataSourceSpecForSettlementData: { __typename?: 'DataSourceSpec', id: string, 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, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType, numberDecimalPlaces?: number | null } }> | null } } | { __typename?: 'DataSourceDefinitionInternal' } } }, dataSourceSpecBinding: { __typename?: 'DataSourceSpecToFutureBinding', settlementDataProperty: string, tradingTerminationProperty: string } } } }, marketTimestamps: { __typename?: 'MarketTimestamps', open: any, close: any } } }> } | null }; export const DataSourceFilterFragmentDoc = gql` fragment DataSourceFilter on Filter { @@ -55,6 +55,8 @@ export const MarketFieldsFragmentDoc = gql` positionDecimalPlaces state tradingMode + parentMarketID + successorMarketID fees { factors { makerFee diff --git a/libs/markets/src/lib/components/index.ts b/libs/markets/src/lib/components/index.ts index 64fd41a55..b8bcfcaea 100644 --- a/libs/markets/src/lib/components/index.ts +++ b/libs/markets/src/lib/components/index.ts @@ -2,7 +2,6 @@ export * from './fees-breakdown'; export * from './last-24h-price-change'; export * from './last-24h-volume'; export * from './market-info'; -export * from './markets-container'; export * from './oracle-banner'; export * from './oracle-basic-profile'; export * from './oracle-full-profile'; diff --git a/libs/markets/src/lib/components/markets-container/index.ts b/libs/markets/src/lib/components/markets-container/index.ts deleted file mode 100644 index 1c9c1e696..000000000 --- a/libs/markets/src/lib/components/markets-container/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './markets-container'; -export * from './market-table-actions'; diff --git a/libs/markets/src/lib/components/markets-container/market-list-table.tsx b/libs/markets/src/lib/components/markets-container/market-list-table.tsx deleted file mode 100644 index a16613077..000000000 --- a/libs/markets/src/lib/components/markets-container/market-list-table.tsx +++ /dev/null @@ -1,69 +0,0 @@ -import type { TypedDataAgGrid } from '@vegaprotocol/datagrid'; -import { - AgGridLazy as AgGrid, - PriceFlashCell, - MarketNameCell, -} from '@vegaprotocol/datagrid'; -import type { MarketMaybeWithData } from '../../markets-provider'; -import { OracleStatus } from './oracle-status'; -import { useColumnDefs } from './use-column-defs'; - -export const getRowId = ({ data }: { data: { id: string } }) => data.id; - -interface MarketNameCellProps { - value?: string; - data?: MarketMaybeWithData; - onMarketClick?: (marketId: string, metaKey?: boolean) => void; -} - -const MarketName = (props: MarketNameCellProps) => ( - <> - - {props.data ? ( - - ) : null} - -); - -const defaultColDef = { - sortable: true, - filter: true, - filterParams: { buttons: ['reset'] }, -}; -type Props = TypedDataAgGrid & { - onMarketClick: (marketId: string, metaKey?: boolean) => void; - SuccessorMarketRenderer?: React.FC<{ value: string }>; -}; -export const MarketListTable = ({ - onMarketClick, - SuccessorMarketRenderer, - ...props -}: Props) => { - const columnDefs = useColumnDefs({ onMarketClick }); - const components = { - PriceFlashCell, - MarketName, - ...(SuccessorMarketRenderer ? { SuccessorMarketRenderer } : null), - }; - return ( - - ); -}; - -export default MarketListTable; diff --git a/libs/markets/src/lib/components/markets-container/markets-container.spec.tsx b/libs/markets/src/lib/components/markets-container/markets-container.spec.tsx deleted file mode 100644 index fe88d1dbc..000000000 --- a/libs/markets/src/lib/components/markets-container/markets-container.spec.tsx +++ /dev/null @@ -1,150 +0,0 @@ -import { render, screen, act, within } from '@testing-library/react'; -import userEvent from '@testing-library/user-event'; -import * as DataProviders from '@vegaprotocol/data-provider'; -import { MockedProvider } from '@apollo/react-testing'; -import type { MarketMaybeWithData } from '../../markets-provider'; -import { MarketsContainer } from './markets-container'; -import { FLAGS } from '@vegaprotocol/environment'; - -jest.mock('@vegaprotocol/environment', () => { - const actual = jest.requireActual('@vegaprotocol/environment'); - return { - ...actual, - FLAGS: { - ...actual.FLAGS, - SUCCESSOR_MARKETS: true, - }, - }; -}); -const SuccessorMarketRenderer = ({ value }: { value: string }) => { - return '-'; -}; - -const market = { - id: 'id-1', - tradableInstrument: { - instrument: { - product: { settlementAsset: { id: 'assetId-1' } }, - }, - }, - decimalPlaces: 1, - positionDecimalPlaces: 1, - state: 'STATE_ACTIVE', - tradingMode: 'TRADING_MODE_OPENING_AUCTION', - data: { - bestBidPrice: 100, - }, -} as unknown as MarketMaybeWithData; - -describe('MarketsContainer', () => { - const spyOnSelect = jest.fn(); - beforeEach(() => { - jest.clearAllMocks(); - - jest - // eslint-disable-next-line @typescript-eslint/no-explicit-any - .spyOn(DataProviders, 'useDataProvider') - .mockImplementation(() => { - return { - error: null, - reload: jest.fn(), - data: [market], - }; - }); - }); - it('context menu should stay open', async () => { - let rerenderRef: (ui: React.ReactElement) => void; - await act(async () => { - const { rerender } = render( - - - - ); - rerenderRef = rerender; - }); - - // make sure ag grid is finished initializaing - const rowContainer = await screen.findByRole('rowgroup', { - name: (_name, element) => - element.classList.contains('ag-center-cols-container'), - }); - expect(within(rowContainer).getAllByRole('row')).toHaveLength(1); - expect( - screen.getByRole('rowgroup', { - name: (_name, element) => - element.classList.contains('ag-pinned-right-cols-container'), - }) - ).toBeInTheDocument(); - - // open the dropdown - await userEvent.click( - screen.getByRole('button', { - name: (_name, element) => - (element.parentNode as Element) - ?.getAttribute('id') - ?.startsWith('cell-market-actions-') || false, - }) - ); - - await checkDropdown(); - - // reset the mock and rerender so the component - // updates with new data - jest - // eslint-disable-next-line @typescript-eslint/no-explicit-any - .spyOn(DataProviders, 'useDataProvider') - .mockImplementation(() => { - return { - error: null, - reload: jest.fn(), - data: [{ ...market, state: 'STATE_PENDING' }], - }; - }); - - // @ts-ignore we await the act above so rerenderRef is definitely defined - rerenderRef( - - - - ); - - // make sure dropdown is still open - await checkDropdown(); - - async function checkDropdown() { - const dropdownContent = await screen.findByTestId( - 'market-actions-content' - ); - expect(dropdownContent).toBeInTheDocument(); - expect( - within(dropdownContent).getByRole('menuitem', { - name: 'Copy Market ID', - }) - ).toBeInTheDocument(); - } - }); - - it('feature flag should hide successorMarketID column', async () => { - const mockedFlags = jest.mocked(FLAGS); - mockedFlags.SUCCESSOR_MARKETS = false; - - const spySuccessorMarketRenderer = jest.fn(); - - render( - - - - ); - - expect(spySuccessorMarketRenderer).not.toHaveBeenCalled(); - screen.getAllByRole('columnheader').forEach((element) => { - expect(element.getAttribute('col-id')).not.toEqual('successorMarketID'); - }); - }); -}); diff --git a/libs/markets/src/lib/components/markets-container/markets-container.tsx b/libs/markets/src/lib/components/markets-container/markets-container.tsx deleted file mode 100644 index 826bd0aac..000000000 --- a/libs/markets/src/lib/components/markets-container/markets-container.tsx +++ /dev/null @@ -1,72 +0,0 @@ -import type { MouseEvent } from 'react'; -import React, { useEffect } from 'react'; -import type { CellClickedEvent } from 'ag-grid-community'; -import { t } from '@vegaprotocol/i18n'; -import { MarketListTable } from './market-list-table'; -import { useDataProvider } from '@vegaprotocol/data-provider'; -import { marketListProvider as dataProvider } from '../../markets-provider'; -import type { MarketMaybeWithData } from '../../markets-provider'; -import { useYesterday } from '@vegaprotocol/react-helpers'; -import { Interval } from '@vegaprotocol/types'; - -const POLLING_TIME = 2000; -interface MarketsContainerProps { - onSelect: (marketId: string, metaKey?: boolean) => void; - SuccessorMarketRenderer?: React.FC<{ value: string }>; -} - -export const MarketsContainer = ({ - onSelect, - SuccessorMarketRenderer, -}: MarketsContainerProps) => { - const yesterday = useYesterday(); - const { data, error, reload } = useDataProvider({ - dataProvider, - variables: { - since: new Date(yesterday).toISOString(), - interval: Interval.INTERVAL_I1H, - }, - }); - - useEffect(() => { - const interval = setInterval(() => { - reload(); - }, POLLING_TIME); - return () => { - clearInterval(interval); - }; - }, [reload]); - - return ( -
- { - const { data, column, event } = cellEvent; - // prevent navigating to the market page if any of the below cells are clicked - // event.preventDefault or event.stopPropagation dont seem to apply for aggird - const colId = column.getColId(); - if ( - [ - 'id', - 'tradableInstrument.instrument.code', - 'tradableInstrument.instrument.product.settlementAsset', - 'tradableInstrument.instrument.product.settlementAsset.symbol', - 'market-actions', - ].includes(colId) - ) { - return; - } - onSelect( - (data as MarketMaybeWithData).id, - (event as unknown as MouseEvent)?.metaKey || - (event as unknown as MouseEvent)?.ctrlKey - ); - }} - onMarketClick={onSelect} - overlayNoRowsTemplate={error ? error.message : t('No markets')} - SuccessorMarketRenderer={SuccessorMarketRenderer} - /> -
- ); -}; diff --git a/libs/markets/src/lib/components/markets-container/oracle-status.tsx b/libs/markets/src/lib/components/markets-container/oracle-status.tsx deleted file mode 100644 index 3165c6ce7..000000000 --- a/libs/markets/src/lib/components/markets-container/oracle-status.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import { useMemo } from 'react'; -import { useEnvironment } from '@vegaprotocol/environment'; -import { Icon } from '@vegaprotocol/ui-toolkit'; -import type { IconName } from '@blueprintjs/icons'; -import { getMatchingOracleProvider, useOracleProofs } from '../../hooks'; -import type { Market } from '../../markets-provider'; -import { getVerifiedStatusIcon } from '../oracle-basic-profile'; - -export const OracleStatus = ({ - dataSourceSpecForSettlementData, - dataSourceSpecForTradingTermination, -}: Pick< - Market['tradableInstrument']['instrument']['product'], - 'dataSourceSpecForSettlementData' | 'dataSourceSpecForTradingTermination' ->) => { - const { ORACLE_PROOFS_URL } = useEnvironment(); - const { data: providers } = useOracleProofs(ORACLE_PROOFS_URL); - return useMemo(() => { - if (providers) { - const settlementDataProvider = getMatchingOracleProvider( - dataSourceSpecForSettlementData.data, - providers - ); - const tradingTerminationDataProvider = getMatchingOracleProvider( - dataSourceSpecForTradingTermination.data, - providers - ); - let maliciousOracleProvider = null; - if (settlementDataProvider?.oracle.status !== 'GOOD') { - maliciousOracleProvider = settlementDataProvider; - } else if (tradingTerminationDataProvider?.oracle.status !== 'GOOD') { - maliciousOracleProvider = tradingTerminationDataProvider; - } - if (!maliciousOracleProvider) return null; - const { icon } = getVerifiedStatusIcon(maliciousOracleProvider); - return ; - } - return null; - }, [ - providers, - dataSourceSpecForSettlementData, - dataSourceSpecForTradingTermination, - ]); -}; diff --git a/libs/markets/src/lib/components/markets-container/summary-cell.tsx b/libs/markets/src/lib/components/markets-container/summary-cell.tsx deleted file mode 100644 index 1d558ee9d..000000000 --- a/libs/markets/src/lib/components/markets-container/summary-cell.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import * as React from 'react'; - -/* -import { useMarketOverview } from '../../../../hooks/use-market-overview' -import { colorByMarketMovement } from '../../../../lib/vega-colours' -import { Sparkline } from '../../components/sparkline' -import { VEGA_TABLE_CLASSES } from '../../components/vega-table' -*/ - -export interface SummaryCellProps { - value: string; // marketId -} - -export const SummaryCellView = ({ value }: SummaryCellProps) => { - // const { sparkline, change, bullish } = useMarketOverview(value) - // const color = colorByMarketMovement(bullish) - - return ( - <> - {/* */} - {'change'} - - ); -}; - -SummaryCellView.displayName = 'SummaryCellView'; - -export const SummaryCell = React.memo(SummaryCellView); -SummaryCell.displayName = 'SummaryCell'; diff --git a/libs/markets/src/lib/components/markets-container/use-column-defs.tsx b/libs/markets/src/lib/components/markets-container/use-column-defs.tsx deleted file mode 100644 index a0511303c..000000000 --- a/libs/markets/src/lib/components/markets-container/use-column-defs.tsx +++ /dev/null @@ -1,231 +0,0 @@ -import { useMemo } from 'react'; -import type { ColDef, ValueFormatterParams } from 'ag-grid-community'; -import compact from 'lodash/compact'; -import { t } from '@vegaprotocol/i18n'; -import type { - VegaICellRendererParams, - VegaValueFormatterParams, - VegaValueGetterParams, -} from '@vegaprotocol/datagrid'; -import { COL_DEFS, SetFilter } from '@vegaprotocol/datagrid'; -import * as Schema from '@vegaprotocol/types'; -import { addDecimalsFormatNumber, toBigNum } from '@vegaprotocol/utils'; -import { ButtonLink, Tooltip } from '@vegaprotocol/ui-toolkit'; -import { useAssetDetailsDialogStore } from '@vegaprotocol/assets'; -import type { - MarketMaybeWithData, - MarketMaybeWithDataAndCandles, -} from '../../markets-provider'; -import { MarketActionsDropdown } from './market-table-actions'; -import { calcCandleVolume } from '../../market-utils'; - -interface Props { - onMarketClick: (marketId: string, metaKey?: boolean) => void; -} - -const { MarketTradingMode, AuctionTrigger } = Schema; - -export const useColumnDefs = ({ onMarketClick }: Props) => { - const { open: openAssetDetailsDialog } = useAssetDetailsDialogStore(); - return useMemo( - () => - compact([ - { - headerName: t('Market'), - field: 'tradableInstrument.instrument.code', - cellRenderer: 'MarketName', - cellRendererParams: { onMarketClick }, - flex: 2, - }, - { - headerName: t('Description'), - field: 'tradableInstrument.instrument.name', - flex: 2, - }, - { - headerName: t('Trading mode'), - field: 'tradingMode', - cellRenderer: ({ - data, - }: VegaICellRendererParams) => { - if (!data?.data) return '-'; - const { trigger, marketTradingMode } = data.data; - - const withTriggerInfo = - marketTradingMode === - MarketTradingMode.TRADING_MODE_MONITORING_AUCTION && - trigger && - trigger !== AuctionTrigger.AUCTION_TRIGGER_UNSPECIFIED; - - if (withTriggerInfo) { - return ( - - - {Schema.MarketTradingModeMapping[marketTradingMode]} - - - ); - } - - return Schema.MarketTradingModeMapping[marketTradingMode]; - }, - filter: SetFilter, - filterParams: { - set: Schema.MarketTradingModeMapping, - }, - }, - { - headerName: t('Status'), - field: 'state', - valueFormatter: ({ - data, - }: VegaValueFormatterParams) => { - return data?.state ? Schema.MarketStateMapping[data.state] : '-'; - }, - filter: SetFilter, - filterParams: { - set: Schema.MarketStateMapping, - }, - }, - { - headerName: t('Mark price'), - field: 'data.markPrice', - type: 'rightAligned', - cellRenderer: 'PriceFlashCell', - filter: 'agNumberColumnFilter', - valueGetter: ({ - data, - }: VegaValueGetterParams) => { - return data?.data?.markPrice === undefined - ? undefined - : toBigNum(data?.data?.markPrice, data.decimalPlaces).toNumber(); - }, - valueFormatter: ({ - data, - }: VegaValueFormatterParams) => - data?.data?.bestOfferPrice === undefined - ? '-' - : addDecimalsFormatNumber( - data.data.markPrice, - data.decimalPlaces - ), - }, - { - headerName: t('24h volume'), - type: 'rightAligned', - field: 'data.candles', - valueGetter: ({ - data, - }: VegaValueGetterParams) => { - if (!data) return 0; - const candles = data?.candles; - const vol = candles ? calcCandleVolume(candles) : '0'; - return Number(vol); - }, - valueFormatter: ({ - data, - }: ValueFormatterParams< - MarketMaybeWithDataAndCandles, - 'candles' - >) => { - const candles = data?.candles; - const vol = candles ? calcCandleVolume(candles) : '0'; - const volume = - data && vol && vol !== '0' - ? addDecimalsFormatNumber(vol, data.positionDecimalPlaces) - : '0.00'; - return volume; - }, - }, - { - headerName: t('Settlement asset'), - field: 'tradableInstrument.instrument.product.settlementAsset.symbol', - cellRenderer: ({ - data, - }: VegaICellRendererParams< - MarketMaybeWithData, - 'tradableInstrument.instrument.product.settlementAsset.symbol' - >) => { - const value = - data?.tradableInstrument.instrument.product.settlementAsset; - return value ? ( - { - openAssetDetailsDialog(value.id, e.target as HTMLElement); - }} - > - {value.symbol} - - ) : ( - '' - ); - }, - }, - { - headerName: t('Spread'), - field: 'data.bestBidPrice', - type: 'rightAligned', - filter: 'agNumberColumnFilter', - cellRenderer: 'PriceFlashCell', - valueGetter: ({ - data, - }: VegaValueGetterParams) => { - if ( - !data || - !data.data?.bestOfferPrice || - !data.data?.bestBidPrice - ) { - return undefined; - } - - const offer = toBigNum( - data.data.bestOfferPrice, - data.decimalPlaces - ); - const bid = toBigNum(data.data.bestBidPrice, data.decimalPlaces); - - const spread = offer.minus(bid).toNumber(); - - // The calculation above can result in '-0' being rendered after formatting - // so return Math.abs to remove it and just render '0' - if (spread === 0) { - return Math.abs(spread); - } - - return spread; - }, - valueFormatter: ({ - value, - }: VegaValueFormatterParams< - MarketMaybeWithData, - 'data.bestBidPrice' - >) => { - if (!value) return '-'; - return value.toString(); - }, - }, - { - colId: 'market-actions', - field: 'id', - ...COL_DEFS.actions, - cellRenderer: ({ - data, - }: VegaICellRendererParams) => { - if (!data) return null; - return ( - - ); - }, - }, - ]), - [onMarketClick, openAssetDetailsDialog] - ); -}; diff --git a/libs/markets/src/lib/components/oracle-basic-profile/oracle-basic-profile.tsx b/libs/markets/src/lib/components/oracle-basic-profile/oracle-basic-profile.tsx index a8afd2966..53531bca1 100644 --- a/libs/markets/src/lib/components/oracle-basic-profile/oracle-basic-profile.tsx +++ b/libs/markets/src/lib/components/oracle-basic-profile/oracle-basic-profile.tsx @@ -43,6 +43,7 @@ export const getVerifiedStatusIcon = (provider: Provider) => { const lastVerified = provider.oracle.last_verified ? new Date(provider.oracle.last_verified) : new Date(provider.oracle.first_verified); + return { ...getIconIntent(), message: t( @@ -112,13 +113,13 @@ export const OracleBasicProfile = ({ -

+

{message}

{oracleMarkets && (

{t('Involved in %s %s', [ oracleMarkets.length.toString(), @@ -130,9 +131,9 @@ export const OracleBasicProfile = ({

{links.map((link) => ( - + - {link.type} + {link.type} diff --git a/libs/markets/src/lib/markets-provider.ts b/libs/markets/src/lib/markets-provider.ts index 021b78fca..c9ded0346 100644 --- a/libs/markets/src/lib/markets-provider.ts +++ b/libs/markets/src/lib/markets-provider.ts @@ -28,8 +28,6 @@ import { } from './market-utils'; import { MarketsDocument } from './__generated__/markets'; import type { Candle } from './market-candles-provider'; -import type { SuccessorMarketIdsQuery } from './__generated__/SuccessorMarket'; -import { SuccessorMarketIdsDocument } from './__generated__'; export type Market = MarketFieldsFragment; @@ -240,34 +238,3 @@ export const useMarketList = () => { reload, }; }; - -export type MarketSuccessors = { - __typename?: 'Market'; - id: string; - successorMarketID?: string | null; - parentMarketID?: string | null; -}; -const getMarketSuccessorData = ( - responseData: SuccessorMarketIdsQuery | null -): MarketSuccessors[] | null => - responseData?.marketsConnection?.edges.map((edge) => edge.node) || null; - -export const marketSuccessorProvider = makeDataProvider< - SuccessorMarketIdsQuery, - MarketSuccessors[], - never, - never ->({ - query: SuccessorMarketIdsDocument, - getData: getMarketSuccessorData, - fetchPolicy: 'no-cache', -}); - -export const useSuccessorMarketIds = (marketId: string) => { - const { data } = useDataProvider({ - dataProvider: marketSuccessorProvider, - variables: undefined, - skip: !marketId, - }); - return data?.find((item) => item.id === marketId) ?? null; -}; diff --git a/libs/markets/src/lib/markets.graphql b/libs/markets/src/lib/markets.graphql index 84e25a6e2..ca424da28 100644 --- a/libs/markets/src/lib/markets.graphql +++ b/libs/markets/src/lib/markets.graphql @@ -36,6 +36,8 @@ fragment MarketFields on Market { positionDecimalPlaces state tradingMode + parentMarketID + successorMarketID fees { factors { makerFee diff --git a/libs/markets/src/lib/markets.mock.ts b/libs/markets/src/lib/markets.mock.ts index 01af90c17..1a9d1ae48 100644 --- a/libs/markets/src/lib/markets.mock.ts +++ b/libs/markets/src/lib/markets.mock.ts @@ -42,6 +42,8 @@ export const createMarketFragment = ( close: null, open: null, }, + successorMarketID: null, + parentMarketID: null, fees: { __typename: 'Fees', factors: { diff --git a/libs/positions/src/lib/positions-table.tsx b/libs/positions/src/lib/positions-table.tsx index a7ef20e93..8d7d5a652 100644 --- a/libs/positions/src/lib/positions-table.tsx +++ b/libs/positions/src/lib/positions-table.tsx @@ -15,6 +15,7 @@ import { MarketNameCell, ProgressBarCell, MarketProductPill, + StackedCell, } from '@vegaprotocol/datagrid'; import { ButtonLink, @@ -40,7 +41,6 @@ import { import { DocsLinks } from '@vegaprotocol/environment'; import { PositionActionsDropdown } from './position-actions-dropdown'; import { LiquidationPrice } from './liquidation-price'; -import { StackedCell } from './stacked-cell'; interface Props extends TypedDataAgGrid { onClose?: (data: Position) => void; diff --git a/libs/proposals/src/components/proposals-list/proposal-list.spec.tsx b/libs/proposals/src/components/proposals-list/proposal-list.spec.tsx index dc003b0e9..80354dbc1 100644 --- a/libs/proposals/src/components/proposals-list/proposal-list.spec.tsx +++ b/libs/proposals/src/components/proposals-list/proposal-list.spec.tsx @@ -1,10 +1,4 @@ -import { - render, - screen, - act, - waitFor, - getAllByRole, -} from '@testing-library/react'; +import { render, screen, waitFor, within } from '@testing-library/react'; import merge from 'lodash/merge'; import type { MockedResponse } from '@apollo/client/testing'; import { MockedProvider } from '@apollo/client/testing'; @@ -14,25 +8,13 @@ import { createProposalListFieldsFragment } from '../../lib/proposals-data-provi import type { ProposalsListQuery } from '../../lib'; import { ProposalsListDocument } from '../../lib'; import type { PartialDeep } from 'type-fest'; -import { FLAGS } from '@vegaprotocol/environment'; -jest.mock('@vegaprotocol/environment', () => { - const actual = jest.requireActual('@vegaprotocol/environment'); - return { - ...actual, - FLAGS: { - ...actual.FLAGS, - SUCCESSOR_MARKETS: true, - }, - }; -}); - -const successorMarketName = 'Successor Market Name'; -const spySuccessorMarketRenderer = jest - .fn() - .mockReturnValue(successorMarketName); +const parentMarketName = 'Parent Market Name'; +const ParentMarketCell = () => {parentMarketName}; describe('ProposalsList', () => { + const rowContainerSelector = '.ag-center-cols-container'; + const createProposalsMock = (override?: PartialDeep) => { const defaultProposalEdges = [ { @@ -81,75 +63,55 @@ describe('ProposalsList', () => { return mock; }; + beforeEach(() => { jest.clearAllMocks(); }); + it('should be properly rendered', async () => { const mock = createProposalsMock(); - await act(() => { - render( - - - - ); - }); - const container = document.querySelector('.ag-center-cols-container'); + render( + + + + ); + await waitFor(() => { - expect(container).toBeInTheDocument(); - }); - expect(getAllByRole(container as HTMLDivElement, 'row')).toHaveLength(3); - }); - - it('some of states should be filtered out', async () => { - const proposalNode = createProposalListFieldsFragment({ - id: 'id-1', - state: Types.ProposalState.STATE_ENACTED, + expect(document.querySelector(rowContainerSelector)).toBeInTheDocument(); }); - const mock = createProposalsMock({ - proposalsConnection: { - edges: [ - { - __typename: 'ProposalEdge', - node: { - ...proposalNode, - terms: { - ...proposalNode.terms, - change: { - ...proposalNode.terms.change, - }, - }, - }, - }, - ], - }, - } as PartialDeep); - await act(() => { - render( - - - - ); - }); - const container = document.querySelector('.ag-center-cols-container'); - await waitFor(() => { - expect(container).toBeInTheDocument(); - expect(getAllByRole(container as HTMLDivElement, 'row')).toHaveLength(2); - }); + const expectedHeaders = [ + 'Market', + 'Settlement asset', + 'State', + 'Parent market', + 'Voting', + 'Closing date', + 'Enactment date', + '', // actions col + ]; - expect(spySuccessorMarketRenderer).toHaveBeenCalled(); + const headers = screen.getAllByRole('columnheader'); + expect(headers).toHaveLength(expectedHeaders.length); expect( - screen.getByRole('columnheader', { - name: (_name, element) => - element.getAttribute('col-id') === 'parentMarket', - }) - ).toBeInTheDocument(); + headers.map((h) => h.querySelector('[ref="eText"]')?.textContent?.trim()) + ).toEqual(expectedHeaders); + + const container = within( + document.querySelector(rowContainerSelector) as HTMLElement + ); + expect(container.getAllByRole('row')).toHaveLength( + // @ts-ignore data is mocked + mock?.result?.data.proposalsConnection.edges.length + ); + expect( - screen.getAllByRole('gridcell', { - name: (name, element) => - element.getAttribute('col-id') === 'parentMarket', + container.getAllByRole('gridcell', { + name: (_, element) => + element.getAttribute('col-id') === + 'terms.change.successorConfiguration.parentMarketId', })[0] - ).toHaveTextContent(successorMarketName); + ).toHaveTextContent(parentMarketName); }); it('empty response should causes no data message display', async () => { @@ -169,58 +131,11 @@ describe('ProposalsList', () => { }, }, }; - await act(() => { - render( - - - - ); - }); - expect(await screen.findByText('No markets')).toBeInTheDocument(); - - expect( - screen.getByRole('columnheader', { - name: (_name, element) => - element.getAttribute('col-id') === 'parentMarket', - }) - ).toBeInTheDocument(); - }); - - it('feature flag should hide parent marketcolumn', async () => { - const mockedFlags = jest.mocked(FLAGS); - mockedFlags.SUCCESSOR_MARKETS = false; - const mock: MockedResponse = { - request: { - query: ProposalsListDocument, - variables: { - proposalType: Types.ProposalType.TYPE_NEW_MARKET, - }, - }, - result: { - data: { - proposalsConnection: { - __typename: 'ProposalsConnection', - edges: [], - }, - }, - }, - }; - await act(() => { - render( - - - - ); - }); - await waitFor(() => { - expect( - screen.getByRole('columnheader', { - name: (_name, element) => element.getAttribute('col-id') === 'market', - }) - ).toBeInTheDocument(); - }); - screen.getAllByRole('columnheader').forEach((element) => { - expect(element.getAttribute('col-id')).not.toEqual('parentMarket'); - }); + render( + + + + ); + expect(await screen.findByText('No proposed markets')).toBeInTheDocument(); }); }); diff --git a/libs/proposals/src/components/proposals-list/proposals-list.tsx b/libs/proposals/src/components/proposals-list/proposals-list.tsx index 9cdb01aef..d4cd1a8c2 100644 --- a/libs/proposals/src/components/proposals-list/proposals-list.tsx +++ b/libs/proposals/src/components/proposals-list/proposals-list.tsx @@ -1,11 +1,11 @@ -import React from 'react'; +import type { FC } from 'react'; import { AgGridLazy as AgGrid } from '@vegaprotocol/datagrid'; import { t } from '@vegaprotocol/i18n'; import * as Types from '@vegaprotocol/types'; -import { MarketNameProposalCell, useColumnDefs } from './use-column-defs'; +import { removePaginationWrapper } from '@vegaprotocol/utils'; import type { ProposalListFieldsFragment } from '../../lib/proposals-data-provider/__generated__/Proposals'; import { useProposalsListQuery } from '../../lib/proposals-data-provider/__generated__/Proposals'; -import { removePaginationWrapper } from '@vegaprotocol/utils'; +import { useColumnDefs } from './use-column-defs'; export const getNewMarketProposals = (data: ProposalListFieldsFragment[]) => data.filter((proposal) => @@ -16,13 +16,19 @@ export const getNewMarketProposals = (data: ProposalListFieldsFragment[]) => ].includes(proposal.state) ); +const defaultColDef = { + sortable: true, + filter: true, + filterParams: { buttons: ['reset'] }, +}; + interface ProposalListProps { - SuccessorMarketRenderer: React.FC<{ value: string }>; + cellRenderers: { + [name: string]: FC<{ value: string; data: ProposalListFieldsFragment }>; + }; } -export const ProposalsList = ({ - SuccessorMarketRenderer, -}: ProposalListProps) => { +export const ProposalsList = ({ cellRenderers }: ProposalListProps) => { const { data } = useProposalsListQuery({ variables: { proposalType: Types.ProposalType.TYPE_NEW_MARKET, @@ -32,7 +38,7 @@ export const ProposalsList = ({ const filteredData = getNewMarketProposals( removePaginationWrapper(data?.proposalsConnection?.edges) ); - const { columnDefs, defaultColDef } = useColumnDefs(); + const columnDefs = useColumnDefs(); return ( data.id} - overlayNoRowsTemplate={t('No markets')} - components={{ SuccessorMarketRenderer, MarketNameProposalCell }} + overlayNoRowsTemplate={t('No proposed markets')} + components={cellRenderers} + rowHeight={45} /> ); }; diff --git a/libs/proposals/src/components/proposals-list/use-column-defs.tsx b/libs/proposals/src/components/proposals-list/use-column-defs.tsx index 795a0fa8c..c0ce65d31 100644 --- a/libs/proposals/src/components/proposals-list/use-column-defs.tsx +++ b/libs/proposals/src/components/proposals-list/use-column-defs.tsx @@ -6,9 +6,9 @@ import { COL_DEFS, DateRangeFilter, SetFilter, + StackedCell, } from '@vegaprotocol/datagrid'; import compact from 'lodash/compact'; -import { useEnvironment, FLAGS } from '@vegaprotocol/environment'; import { getDateTimeFormat } from '@vegaprotocol/utils'; import { t } from '@vegaprotocol/i18n'; import { @@ -19,50 +19,15 @@ import type { VegaICellRendererParams, VegaValueFormatterParams, } from '@vegaprotocol/datagrid'; -import { ExternalLink, Pill } from '@vegaprotocol/ui-toolkit'; import { - ProposalProductTypeMapping, - ProposalProductTypeShortName, + ProductTypeMapping, + ProductTypeShortName, ProposalStateMapping, } from '@vegaprotocol/types'; import type { ProposalListFieldsFragment } from '../../lib/proposals-data-provider/__generated__/Proposals'; import { VoteProgress } from '../voting-progress'; import { ProposalActionsDropdown } from '../proposal-actions-dropdown'; -export const MarketNameProposalCell = ({ - value, - data, -}: VegaICellRendererParams< - ProposalListFieldsFragment, - 'terms.change.instrument.code' ->) => { - const { VEGA_TOKEN_URL } = useEnvironment(); - const { change } = data?.terms || {}; - if (change?.__typename === 'NewMarket' && VEGA_TOKEN_URL) { - const type = change.instrument.futureProduct?.__typename; - const content = ( - <> - {value as string} - {type && ( - - {ProposalProductTypeShortName[type]} - - )} - - ); - if (data?.id) { - const link = `${VEGA_TOKEN_URL}/proposals/${data.id}`; - return {content}; - } - return content; - } - return null; -}; - export const useColumnDefs = () => { const { params } = useNetworkParams([ NetworkParams.governance_proposal_market_requiredMajority, @@ -80,17 +45,36 @@ export const useColumnDefs = () => { headerName: t('Market'), field: 'terms.change.instrument.code', cellStyle: { lineHeight: '14px' }, - cellRenderer: 'MarketNameProposalCell', - }, - { - colId: 'description', - headerName: t('Description'), - field: 'terms.change.instrument.name', + cellRenderer: ({ + value, + data, + }: { + value: string; + data: ProposalListFieldsFragment; + }) => { + if (!value || !data) return '-'; + + // TODO: update when we switch to ProductConfiguration + const productType = 'Future'; + return ( + + {ProductTypeShortName[productType]} + + } + /> + ); + }, }, { colId: 'asset', headerName: t('Settlement asset'), - field: 'terms.change.instrument.futureProduct.settlementAsset.name', + field: 'terms.change.instrument.futureProduct.settlementAsset.symbol', }, { colId: 'state', @@ -105,12 +89,10 @@ export const useColumnDefs = () => { set: ProposalStateMapping, }, }, - FLAGS.SUCCESSOR_MARKETS && { + { headerName: t('Parent market'), - field: 'id', - colId: 'parentMarket', - cellRenderer: 'SuccessorMarketRenderer', - cellRendererParams: { parent: true }, + field: 'terms.change.successorConfiguration.parentMarketId', + cellRenderer: 'ParentMarketCell', }, { colId: 'voting', @@ -169,25 +151,12 @@ export const useColumnDefs = () => { data, }: VegaICellRendererParams) => { if (!data?.id) return null; + return ; }, }, ]); }, [requiredMajorityPercentage]); - const defaultColDef: ColDef = useMemo(() => { - return { - sortable: true, - filter: true, - filterParams: { buttons: ['reset'] }, - }; - }, []); - - return useMemo( - () => ({ - columnDefs, - defaultColDef, - }), - [columnDefs, defaultColDef] - ); + return columnDefs; }; diff --git a/libs/proposals/src/lib/proposals-data-provider/Proposals.graphql b/libs/proposals/src/lib/proposals-data-provider/Proposals.graphql index dde320b6c..1429c9107 100644 --- a/libs/proposals/src/lib/proposals-data-provider/Proposals.graphql +++ b/libs/proposals/src/lib/proposals-data-provider/Proposals.graphql @@ -114,6 +114,9 @@ fragment NewMarketFields on NewMarket { lpPriceRange # linearSlippageFactor # quadraticSlippageFactor + successorConfiguration { + parentMarketId + } } fragment UpdateMarketFields on UpdateMarket { diff --git a/libs/proposals/src/lib/proposals-data-provider/__generated__/Proposals.ts b/libs/proposals/src/lib/proposals-data-provider/__generated__/Proposals.ts index 8f4c71956..90aa2c975 100644 --- a/libs/proposals/src/lib/proposals-data-provider/__generated__/Proposals.ts +++ b/libs/proposals/src/lib/proposals-data-provider/__generated__/Proposals.ts @@ -3,7 +3,7 @@ import * as Types from '@vegaprotocol/types'; import { gql } from '@apollo/client'; import * as Apollo from '@apollo/client'; const defaultOptions = {} as const; -export type NewMarketFieldsFragment = { __typename?: 'NewMarket', decimalPlaces: number, metadata?: Array | null, lpPriceRange: string, instrument: { __typename?: 'InstrumentConfiguration', name: string, code: string, futureProduct?: { __typename?: 'FutureProduct', quoteName: string, settlementAsset: { __typename?: 'Asset', id: string, name: string, symbol: string, decimals: number, quantum: string }, dataSourceSpecForSettlementData: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType }, conditions?: Array<{ __typename?: 'Condition', operator: Types.ConditionOperator, value?: string | null }> | null }> | null } } | { __typename?: 'DataSourceDefinitionInternal' } }, dataSourceSpecForTradingTermination: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType }, conditions?: Array<{ __typename?: 'Condition', operator: Types.ConditionOperator, value?: string | null }> | null }> | null } } | { __typename?: 'DataSourceDefinitionInternal' } }, dataSourceSpecBinding: { __typename?: 'DataSourceSpecToFutureBinding', settlementDataProperty: string, tradingTerminationProperty: string } } | null }, riskParameters: { __typename?: 'LogNormalRiskModel', riskAversionParameter: number, tau: number, params: { __typename?: 'LogNormalModelParams', mu: number, r: number, sigma: number } } | { __typename?: 'SimpleRiskModel', params: { __typename?: 'SimpleRiskModelParams', factorLong: number, factorShort: number } } }; +export type NewMarketFieldsFragment = { __typename?: 'NewMarket', decimalPlaces: number, metadata?: Array | null, lpPriceRange: string, instrument: { __typename?: 'InstrumentConfiguration', name: string, code: string, futureProduct?: { __typename?: 'FutureProduct', quoteName: string, settlementAsset: { __typename?: 'Asset', id: string, name: string, symbol: string, decimals: number, quantum: string }, dataSourceSpecForSettlementData: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType }, conditions?: Array<{ __typename?: 'Condition', operator: Types.ConditionOperator, value?: string | null }> | null }> | null } } | { __typename?: 'DataSourceDefinitionInternal' } }, dataSourceSpecForTradingTermination: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType }, conditions?: Array<{ __typename?: 'Condition', operator: Types.ConditionOperator, value?: string | null }> | null }> | null } } | { __typename?: 'DataSourceDefinitionInternal' } }, dataSourceSpecBinding: { __typename?: 'DataSourceSpecToFutureBinding', settlementDataProperty: string, tradingTerminationProperty: string } } | null }, riskParameters: { __typename?: 'LogNormalRiskModel', riskAversionParameter: number, tau: number, params: { __typename?: 'LogNormalModelParams', mu: number, r: number, sigma: number } } | { __typename?: 'SimpleRiskModel', params: { __typename?: 'SimpleRiskModelParams', factorLong: number, factorShort: number } }, successorConfiguration?: { __typename?: 'SuccessorConfiguration', parentMarketId: string } | null }; export type UpdateMarketFieldsFragment = { __typename?: 'UpdateMarket', marketId: string, updateMarketConfiguration: { __typename?: 'UpdateMarketConfiguration', metadata?: Array | null, instrument: { __typename?: 'UpdateInstrumentConfiguration', code: string, product: { __typename?: 'UpdateFutureProduct', quoteName: string, dataSourceSpecForSettlementData: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType }, conditions?: Array<{ __typename?: 'Condition', operator: Types.ConditionOperator, value?: string | null }> | null }> | null } } | { __typename?: 'DataSourceDefinitionInternal' } }, dataSourceSpecForTradingTermination: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType }, conditions?: Array<{ __typename?: 'Condition', operator: Types.ConditionOperator, value?: string | null }> | null }> | null } } | { __typename?: 'DataSourceDefinitionInternal' } }, dataSourceSpecBinding: { __typename?: 'DataSourceSpecToFutureBinding', settlementDataProperty: string, tradingTerminationProperty: string } } }, priceMonitoringParameters: { __typename?: 'PriceMonitoringParameters', triggers?: Array<{ __typename?: 'PriceMonitoringTrigger', horizonSecs: number, probability: number, auctionExtensionSecs: number }> | null }, liquidityMonitoringParameters: { __typename?: 'LiquidityMonitoringParameters', triggeringRatio: string, targetStakeParameters: { __typename?: 'TargetStakeParameters', timeWindow: number, scalingFactor: number } }, riskParameters: { __typename: 'UpdateMarketLogNormalRiskModel', logNormal?: { __typename?: 'LogNormalRiskModel', riskAversionParameter: number, tau: number, params: { __typename?: 'LogNormalModelParams', mu: number, r: number, sigma: number } } | null } | { __typename: 'UpdateMarketSimpleRiskModel', simple?: { __typename?: 'SimpleRiskModelParams', factorLong: number, factorShort: number } | null } } }; @@ -13,7 +13,7 @@ export type UpdateAssetFieldsFragment = { __typename?: 'UpdateAsset', assetId: s export type UpdateNetworkParameterFielsFragment = { __typename?: 'UpdateNetworkParameter', networkParameter: { __typename?: 'NetworkParameter', key: string, value: string } }; -export type ProposalListFieldsFragment = { __typename?: 'Proposal', id?: string | null, reference: string, state: Types.ProposalState, datetime: any, rejectionReason?: Types.ProposalRejectionReason | null, errorDetails?: string | null, requiredMajority: string, requiredParticipation: string, requiredLpMajority?: string | null, requiredLpParticipation?: string | null, rationale: { __typename?: 'ProposalRationale', title: string, description: string }, party: { __typename?: 'Party', id: string }, votes: { __typename?: 'ProposalVotes', yes: { __typename?: 'ProposalVoteSide', totalTokens: string, totalNumber: string, totalWeight: string }, no: { __typename?: 'ProposalVoteSide', totalTokens: string, totalNumber: string, totalWeight: string } }, terms: { __typename?: 'ProposalTerms', closingDatetime: any, enactmentDatetime?: any | null, change: { __typename: 'CancelTransfer' } | { __typename: 'NewAsset', name: string, symbol: string, decimals: number, quantum: string, source: { __typename?: 'BuiltinAsset', maxFaucetAmountMint: string } | { __typename?: 'ERC20', contractAddress: string, lifetimeLimit: string, withdrawThreshold: string } } | { __typename: 'NewFreeform' } | { __typename: 'NewMarket', decimalPlaces: number, metadata?: Array | null, lpPriceRange: string, instrument: { __typename?: 'InstrumentConfiguration', name: string, code: string, futureProduct?: { __typename?: 'FutureProduct', quoteName: string, settlementAsset: { __typename?: 'Asset', id: string, name: string, symbol: string, decimals: number, quantum: string }, dataSourceSpecForSettlementData: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType }, conditions?: Array<{ __typename?: 'Condition', operator: Types.ConditionOperator, value?: string | null }> | null }> | null } } | { __typename?: 'DataSourceDefinitionInternal' } }, dataSourceSpecForTradingTermination: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType }, conditions?: Array<{ __typename?: 'Condition', operator: Types.ConditionOperator, value?: string | null }> | null }> | null } } | { __typename?: 'DataSourceDefinitionInternal' } }, dataSourceSpecBinding: { __typename?: 'DataSourceSpecToFutureBinding', settlementDataProperty: string, tradingTerminationProperty: string } } | null }, riskParameters: { __typename?: 'LogNormalRiskModel', riskAversionParameter: number, tau: number, params: { __typename?: 'LogNormalModelParams', mu: number, r: number, sigma: number } } | { __typename?: 'SimpleRiskModel', params: { __typename?: 'SimpleRiskModelParams', factorLong: number, factorShort: number } } } | { __typename: 'NewTransfer' } | { __typename: 'UpdateAsset', assetId: string, quantum: string, source: { __typename?: 'UpdateERC20', lifetimeLimit: string, withdrawThreshold: string } } | { __typename: 'UpdateMarket', marketId: string, updateMarketConfiguration: { __typename?: 'UpdateMarketConfiguration', metadata?: Array | null, instrument: { __typename?: 'UpdateInstrumentConfiguration', code: string, product: { __typename?: 'UpdateFutureProduct', quoteName: string, dataSourceSpecForSettlementData: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType }, conditions?: Array<{ __typename?: 'Condition', operator: Types.ConditionOperator, value?: string | null }> | null }> | null } } | { __typename?: 'DataSourceDefinitionInternal' } }, dataSourceSpecForTradingTermination: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType }, conditions?: Array<{ __typename?: 'Condition', operator: Types.ConditionOperator, value?: string | null }> | null }> | null } } | { __typename?: 'DataSourceDefinitionInternal' } }, dataSourceSpecBinding: { __typename?: 'DataSourceSpecToFutureBinding', settlementDataProperty: string, tradingTerminationProperty: string } } }, priceMonitoringParameters: { __typename?: 'PriceMonitoringParameters', triggers?: Array<{ __typename?: 'PriceMonitoringTrigger', horizonSecs: number, probability: number, auctionExtensionSecs: number }> | null }, liquidityMonitoringParameters: { __typename?: 'LiquidityMonitoringParameters', triggeringRatio: string, targetStakeParameters: { __typename?: 'TargetStakeParameters', timeWindow: number, scalingFactor: number } }, riskParameters: { __typename: 'UpdateMarketLogNormalRiskModel', logNormal?: { __typename?: 'LogNormalRiskModel', riskAversionParameter: number, tau: number, params: { __typename?: 'LogNormalModelParams', mu: number, r: number, sigma: number } } | null } | { __typename: 'UpdateMarketSimpleRiskModel', simple?: { __typename?: 'SimpleRiskModelParams', factorLong: number, factorShort: number } | null } } } | { __typename: 'UpdateNetworkParameter', networkParameter: { __typename?: 'NetworkParameter', key: string, value: string } } } }; +export type ProposalListFieldsFragment = { __typename?: 'Proposal', id?: string | null, reference: string, state: Types.ProposalState, datetime: any, rejectionReason?: Types.ProposalRejectionReason | null, errorDetails?: string | null, requiredMajority: string, requiredParticipation: string, requiredLpMajority?: string | null, requiredLpParticipation?: string | null, rationale: { __typename?: 'ProposalRationale', title: string, description: string }, party: { __typename?: 'Party', id: string }, votes: { __typename?: 'ProposalVotes', yes: { __typename?: 'ProposalVoteSide', totalTokens: string, totalNumber: string, totalWeight: string }, no: { __typename?: 'ProposalVoteSide', totalTokens: string, totalNumber: string, totalWeight: string } }, terms: { __typename?: 'ProposalTerms', closingDatetime: any, enactmentDatetime?: any | null, change: { __typename: 'CancelTransfer' } | { __typename: 'NewAsset', name: string, symbol: string, decimals: number, quantum: string, source: { __typename?: 'BuiltinAsset', maxFaucetAmountMint: string } | { __typename?: 'ERC20', contractAddress: string, lifetimeLimit: string, withdrawThreshold: string } } | { __typename: 'NewFreeform' } | { __typename: 'NewMarket', decimalPlaces: number, metadata?: Array | null, lpPriceRange: string, instrument: { __typename?: 'InstrumentConfiguration', name: string, code: string, futureProduct?: { __typename?: 'FutureProduct', quoteName: string, settlementAsset: { __typename?: 'Asset', id: string, name: string, symbol: string, decimals: number, quantum: string }, dataSourceSpecForSettlementData: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType }, conditions?: Array<{ __typename?: 'Condition', operator: Types.ConditionOperator, value?: string | null }> | null }> | null } } | { __typename?: 'DataSourceDefinitionInternal' } }, dataSourceSpecForTradingTermination: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType }, conditions?: Array<{ __typename?: 'Condition', operator: Types.ConditionOperator, value?: string | null }> | null }> | null } } | { __typename?: 'DataSourceDefinitionInternal' } }, dataSourceSpecBinding: { __typename?: 'DataSourceSpecToFutureBinding', settlementDataProperty: string, tradingTerminationProperty: string } } | null }, riskParameters: { __typename?: 'LogNormalRiskModel', riskAversionParameter: number, tau: number, params: { __typename?: 'LogNormalModelParams', mu: number, r: number, sigma: number } } | { __typename?: 'SimpleRiskModel', params: { __typename?: 'SimpleRiskModelParams', factorLong: number, factorShort: number } }, successorConfiguration?: { __typename?: 'SuccessorConfiguration', parentMarketId: string } | null } | { __typename: 'NewTransfer' } | { __typename: 'UpdateAsset', assetId: string, quantum: string, source: { __typename?: 'UpdateERC20', lifetimeLimit: string, withdrawThreshold: string } } | { __typename: 'UpdateMarket', marketId: string, updateMarketConfiguration: { __typename?: 'UpdateMarketConfiguration', metadata?: Array | null, instrument: { __typename?: 'UpdateInstrumentConfiguration', code: string, product: { __typename?: 'UpdateFutureProduct', quoteName: string, dataSourceSpecForSettlementData: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType }, conditions?: Array<{ __typename?: 'Condition', operator: Types.ConditionOperator, value?: string | null }> | null }> | null } } | { __typename?: 'DataSourceDefinitionInternal' } }, dataSourceSpecForTradingTermination: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType }, conditions?: Array<{ __typename?: 'Condition', operator: Types.ConditionOperator, value?: string | null }> | null }> | null } } | { __typename?: 'DataSourceDefinitionInternal' } }, dataSourceSpecBinding: { __typename?: 'DataSourceSpecToFutureBinding', settlementDataProperty: string, tradingTerminationProperty: string } } }, priceMonitoringParameters: { __typename?: 'PriceMonitoringParameters', triggers?: Array<{ __typename?: 'PriceMonitoringTrigger', horizonSecs: number, probability: number, auctionExtensionSecs: number }> | null }, liquidityMonitoringParameters: { __typename?: 'LiquidityMonitoringParameters', triggeringRatio: string, targetStakeParameters: { __typename?: 'TargetStakeParameters', timeWindow: number, scalingFactor: number } }, riskParameters: { __typename: 'UpdateMarketLogNormalRiskModel', logNormal?: { __typename?: 'LogNormalRiskModel', riskAversionParameter: number, tau: number, params: { __typename?: 'LogNormalModelParams', mu: number, r: number, sigma: number } } | null } | { __typename: 'UpdateMarketSimpleRiskModel', simple?: { __typename?: 'SimpleRiskModelParams', factorLong: number, factorShort: number } | null } } } | { __typename: 'UpdateNetworkParameter', networkParameter: { __typename?: 'NetworkParameter', key: string, value: string } } } }; export type ProposalsListQueryVariables = Types.Exact<{ proposalType?: Types.InputMaybe; @@ -21,7 +21,7 @@ export type ProposalsListQueryVariables = Types.Exact<{ }>; -export type ProposalsListQuery = { __typename?: 'Query', proposalsConnection?: { __typename?: 'ProposalsConnection', edges?: Array<{ __typename?: 'ProposalEdge', node: { __typename?: 'Proposal', id?: string | null, reference: string, state: Types.ProposalState, datetime: any, rejectionReason?: Types.ProposalRejectionReason | null, errorDetails?: string | null, requiredMajority: string, requiredParticipation: string, requiredLpMajority?: string | null, requiredLpParticipation?: string | null, rationale: { __typename?: 'ProposalRationale', title: string, description: string }, party: { __typename?: 'Party', id: string }, votes: { __typename?: 'ProposalVotes', yes: { __typename?: 'ProposalVoteSide', totalTokens: string, totalNumber: string, totalWeight: string }, no: { __typename?: 'ProposalVoteSide', totalTokens: string, totalNumber: string, totalWeight: string } }, terms: { __typename?: 'ProposalTerms', closingDatetime: any, enactmentDatetime?: any | null, change: { __typename: 'CancelTransfer' } | { __typename: 'NewAsset', name: string, symbol: string, decimals: number, quantum: string, source: { __typename?: 'BuiltinAsset', maxFaucetAmountMint: string } | { __typename?: 'ERC20', contractAddress: string, lifetimeLimit: string, withdrawThreshold: string } } | { __typename: 'NewFreeform' } | { __typename: 'NewMarket', decimalPlaces: number, metadata?: Array | null, lpPriceRange: string, instrument: { __typename?: 'InstrumentConfiguration', name: string, code: string, futureProduct?: { __typename?: 'FutureProduct', quoteName: string, settlementAsset: { __typename?: 'Asset', id: string, name: string, symbol: string, decimals: number, quantum: string }, dataSourceSpecForSettlementData: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType }, conditions?: Array<{ __typename?: 'Condition', operator: Types.ConditionOperator, value?: string | null }> | null }> | null } } | { __typename?: 'DataSourceDefinitionInternal' } }, dataSourceSpecForTradingTermination: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType }, conditions?: Array<{ __typename?: 'Condition', operator: Types.ConditionOperator, value?: string | null }> | null }> | null } } | { __typename?: 'DataSourceDefinitionInternal' } }, dataSourceSpecBinding: { __typename?: 'DataSourceSpecToFutureBinding', settlementDataProperty: string, tradingTerminationProperty: string } } | null }, riskParameters: { __typename?: 'LogNormalRiskModel', riskAversionParameter: number, tau: number, params: { __typename?: 'LogNormalModelParams', mu: number, r: number, sigma: number } } | { __typename?: 'SimpleRiskModel', params: { __typename?: 'SimpleRiskModelParams', factorLong: number, factorShort: number } } } | { __typename: 'NewTransfer' } | { __typename: 'UpdateAsset', assetId: string, quantum: string, source: { __typename?: 'UpdateERC20', lifetimeLimit: string, withdrawThreshold: string } } | { __typename: 'UpdateMarket', marketId: string, updateMarketConfiguration: { __typename?: 'UpdateMarketConfiguration', metadata?: Array | null, instrument: { __typename?: 'UpdateInstrumentConfiguration', code: string, product: { __typename?: 'UpdateFutureProduct', quoteName: string, dataSourceSpecForSettlementData: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType }, conditions?: Array<{ __typename?: 'Condition', operator: Types.ConditionOperator, value?: string | null }> | null }> | null } } | { __typename?: 'DataSourceDefinitionInternal' } }, dataSourceSpecForTradingTermination: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType }, conditions?: Array<{ __typename?: 'Condition', operator: Types.ConditionOperator, value?: string | null }> | null }> | null } } | { __typename?: 'DataSourceDefinitionInternal' } }, dataSourceSpecBinding: { __typename?: 'DataSourceSpecToFutureBinding', settlementDataProperty: string, tradingTerminationProperty: string } } }, priceMonitoringParameters: { __typename?: 'PriceMonitoringParameters', triggers?: Array<{ __typename?: 'PriceMonitoringTrigger', horizonSecs: number, probability: number, auctionExtensionSecs: number }> | null }, liquidityMonitoringParameters: { __typename?: 'LiquidityMonitoringParameters', triggeringRatio: string, targetStakeParameters: { __typename?: 'TargetStakeParameters', timeWindow: number, scalingFactor: number } }, riskParameters: { __typename: 'UpdateMarketLogNormalRiskModel', logNormal?: { __typename?: 'LogNormalRiskModel', riskAversionParameter: number, tau: number, params: { __typename?: 'LogNormalModelParams', mu: number, r: number, sigma: number } } | null } | { __typename: 'UpdateMarketSimpleRiskModel', simple?: { __typename?: 'SimpleRiskModelParams', factorLong: number, factorShort: number } | null } } } | { __typename: 'UpdateNetworkParameter', networkParameter: { __typename?: 'NetworkParameter', key: string, value: string } } } } } | null> | null } | null }; +export type ProposalsListQuery = { __typename?: 'Query', proposalsConnection?: { __typename?: 'ProposalsConnection', edges?: Array<{ __typename?: 'ProposalEdge', node: { __typename?: 'Proposal', id?: string | null, reference: string, state: Types.ProposalState, datetime: any, rejectionReason?: Types.ProposalRejectionReason | null, errorDetails?: string | null, requiredMajority: string, requiredParticipation: string, requiredLpMajority?: string | null, requiredLpParticipation?: string | null, rationale: { __typename?: 'ProposalRationale', title: string, description: string }, party: { __typename?: 'Party', id: string }, votes: { __typename?: 'ProposalVotes', yes: { __typename?: 'ProposalVoteSide', totalTokens: string, totalNumber: string, totalWeight: string }, no: { __typename?: 'ProposalVoteSide', totalTokens: string, totalNumber: string, totalWeight: string } }, terms: { __typename?: 'ProposalTerms', closingDatetime: any, enactmentDatetime?: any | null, change: { __typename: 'CancelTransfer' } | { __typename: 'NewAsset', name: string, symbol: string, decimals: number, quantum: string, source: { __typename?: 'BuiltinAsset', maxFaucetAmountMint: string } | { __typename?: 'ERC20', contractAddress: string, lifetimeLimit: string, withdrawThreshold: string } } | { __typename: 'NewFreeform' } | { __typename: 'NewMarket', decimalPlaces: number, metadata?: Array | null, lpPriceRange: string, instrument: { __typename?: 'InstrumentConfiguration', name: string, code: string, futureProduct?: { __typename?: 'FutureProduct', quoteName: string, settlementAsset: { __typename?: 'Asset', id: string, name: string, symbol: string, decimals: number, quantum: string }, dataSourceSpecForSettlementData: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType }, conditions?: Array<{ __typename?: 'Condition', operator: Types.ConditionOperator, value?: string | null }> | null }> | null } } | { __typename?: 'DataSourceDefinitionInternal' } }, dataSourceSpecForTradingTermination: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType }, conditions?: Array<{ __typename?: 'Condition', operator: Types.ConditionOperator, value?: string | null }> | null }> | null } } | { __typename?: 'DataSourceDefinitionInternal' } }, dataSourceSpecBinding: { __typename?: 'DataSourceSpecToFutureBinding', settlementDataProperty: string, tradingTerminationProperty: string } } | null }, riskParameters: { __typename?: 'LogNormalRiskModel', riskAversionParameter: number, tau: number, params: { __typename?: 'LogNormalModelParams', mu: number, r: number, sigma: number } } | { __typename?: 'SimpleRiskModel', params: { __typename?: 'SimpleRiskModelParams', factorLong: number, factorShort: number } }, successorConfiguration?: { __typename?: 'SuccessorConfiguration', parentMarketId: string } | null } | { __typename: 'NewTransfer' } | { __typename: 'UpdateAsset', assetId: string, quantum: string, source: { __typename?: 'UpdateERC20', lifetimeLimit: string, withdrawThreshold: string } } | { __typename: 'UpdateMarket', marketId: string, updateMarketConfiguration: { __typename?: 'UpdateMarketConfiguration', metadata?: Array | null, instrument: { __typename?: 'UpdateInstrumentConfiguration', code: string, product: { __typename?: 'UpdateFutureProduct', quoteName: string, dataSourceSpecForSettlementData: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType }, conditions?: Array<{ __typename?: 'Condition', operator: Types.ConditionOperator, value?: string | null }> | null }> | null } } | { __typename?: 'DataSourceDefinitionInternal' } }, dataSourceSpecForTradingTermination: { __typename?: 'DataSourceDefinition', sourceType: { __typename?: 'DataSourceDefinitionExternal', sourceType: { __typename?: 'DataSourceSpecConfiguration', signers?: Array<{ __typename?: 'Signer', signer: { __typename?: 'ETHAddress', address?: string | null } | { __typename?: 'PubKey', key?: string | null } }> | null, filters?: Array<{ __typename?: 'Filter', key: { __typename?: 'PropertyKey', name?: string | null, type: Types.PropertyKeyType }, conditions?: Array<{ __typename?: 'Condition', operator: Types.ConditionOperator, value?: string | null }> | null }> | null } } | { __typename?: 'DataSourceDefinitionInternal' } }, dataSourceSpecBinding: { __typename?: 'DataSourceSpecToFutureBinding', settlementDataProperty: string, tradingTerminationProperty: string } } }, priceMonitoringParameters: { __typename?: 'PriceMonitoringParameters', triggers?: Array<{ __typename?: 'PriceMonitoringTrigger', horizonSecs: number, probability: number, auctionExtensionSecs: number }> | null }, liquidityMonitoringParameters: { __typename?: 'LiquidityMonitoringParameters', triggeringRatio: string, targetStakeParameters: { __typename?: 'TargetStakeParameters', timeWindow: number, scalingFactor: number } }, riskParameters: { __typename: 'UpdateMarketLogNormalRiskModel', logNormal?: { __typename?: 'LogNormalRiskModel', riskAversionParameter: number, tau: number, params: { __typename?: 'LogNormalModelParams', mu: number, r: number, sigma: number } } | null } | { __typename: 'UpdateMarketSimpleRiskModel', simple?: { __typename?: 'SimpleRiskModelParams', factorLong: number, factorShort: number } | null } } } | { __typename: 'UpdateNetworkParameter', networkParameter: { __typename?: 'NetworkParameter', key: string, value: string } } } } } | null> | null } | null }; export type NewMarketSuccessorFieldsFragment = { __typename?: 'NewMarket', instrument: { __typename?: 'InstrumentConfiguration', name: string }, successorConfiguration?: { __typename?: 'SuccessorConfiguration', parentMarketId: string } | null }; @@ -132,6 +132,9 @@ export const NewMarketFieldsFragmentDoc = gql` } metadata lpPriceRange + successorConfiguration { + parentMarketId + } } `; export const UpdateMarketFieldsFragmentDoc = gql` diff --git a/libs/proposals/src/lib/proposals-data-provider/proposals.mock.ts b/libs/proposals/src/lib/proposals-data-provider/proposals.mock.ts index 3b8add493..2fd351dee 100644 --- a/libs/proposals/src/lib/proposals-data-provider/proposals.mock.ts +++ b/libs/proposals/src/lib/proposals-data-provider/proposals.mock.ts @@ -109,6 +109,58 @@ export const marketUpdateProposal: ProposalListFieldsFragment = { export const createProposalListFieldsFragment = ( override?: PartialDeep ): ProposalListFieldsFragment => { + const newMarket = { + decimalPlaces: 1, + lpPriceRange: '', + riskParameters: { + __typename: 'SimpleRiskModel', + params: { + __typename: 'SimpleRiskModelParams', + factorLong: 0, + factorShort: 1, + }, + }, + metadata: undefined, + successorConfiguration: { + __typename: 'SuccessorConfiguration', + parentMarketId: 'xyz', + }, + instrument: { + code: 'ETHUSD', + name: 'ETHUSD', + futureProduct: { + settlementAsset: { + id: 'b340c130096819428a62e5df407fd6abe66e444b89ad64f670beb98621c9c663', + name: 'tDAI TEST', + symbol: 'tDAI', + decimals: 1, + quantum: '1', + __typename: 'Asset', + }, + quoteName: '', + dataSourceSpecBinding: { + __typename: 'DataSourceSpecToFutureBinding', + settlementDataProperty: '', + tradingTerminationProperty: '', + }, + dataSourceSpecForSettlementData: { + __typename: 'DataSourceDefinition', + sourceType: { + __typename: 'DataSourceDefinitionInternal', + }, + }, + dataSourceSpecForTradingTermination: { + __typename: 'DataSourceDefinition', + sourceType: { + __typename: 'DataSourceDefinitionInternal', + }, + }, + __typename: 'FutureProduct', + }, + __typename: 'InstrumentConfiguration', + }, + __typename: 'NewMarket', + } as const; const defaultProposal: ProposalListFieldsFragment = { id: 'e9ec6d5c46a7e7bcabf9ba7a893fa5a5eeeec08b731f06f7a6eb7bf0e605b829', reference: 'injected_at_runtime', @@ -147,54 +199,7 @@ export const createProposalListFieldsFragment = ( terms: { closingDatetime: '2022-11-15T12:44:34Z', enactmentDatetime: '2022-11-15T12:44:54Z', - change: { - decimalPlaces: 1, - lpPriceRange: '', - riskParameters: { - __typename: 'SimpleRiskModel', - params: { - __typename: 'SimpleRiskModelParams', - factorLong: 0, - factorShort: 1, - }, - }, - metadata: [], - instrument: { - code: 'ETHUSD', - name: 'ETHUSD', - futureProduct: { - settlementAsset: { - id: 'b340c130096819428a62e5df407fd6abe66e444b89ad64f670beb98621c9c663', - name: 'tDAI TEST', - symbol: 'tDAI', - decimals: 1, - quantum: '1', - __typename: 'Asset', - }, - quoteName: '', - dataSourceSpecBinding: { - __typename: 'DataSourceSpecToFutureBinding', - settlementDataProperty: '', - tradingTerminationProperty: '', - }, - dataSourceSpecForSettlementData: { - __typename: 'DataSourceDefinition', - sourceType: { - __typename: 'DataSourceDefinitionInternal', - }, - }, - dataSourceSpecForTradingTermination: { - __typename: 'DataSourceDefinition', - sourceType: { - __typename: 'DataSourceDefinitionInternal', - }, - }, - __typename: 'FutureProduct', - }, - __typename: 'InstrumentConfiguration', - }, - __typename: 'NewMarket', - }, + change: newMarket, __typename: 'ProposalTerms', }, __typename: 'Proposal', From 250a654544f6274cdb96809e26a7880ba178f531 Mon Sep 17 00:00:00 2001 From: "m.ray" <16125548+MadalinaRaicu@users.noreply.github.com> Date: Tue, 12 Sep 2023 22:06:47 +0300 Subject: [PATCH 08/31] feat(trading): margin required progressive disclosure (#4755) --- apps/trading/.env | 23 ++--- .../deal-ticket/deal-ticket-fee-details.tsx | 96 ++++++++++++------- .../deal-ticket/deal-ticket-stop-order.tsx | 2 +- .../components/deal-ticket/deal-ticket.tsx | 2 +- .../src/components/deal-ticket/key-value.tsx | 10 +- libs/deal-ticket/src/constants.ts | 4 +- .../src/components/accordion/accordion.tsx | 37 ++++++- .../src/components/tooltip/tooltip.tsx | 12 ++- 8 files changed, 125 insertions(+), 61 deletions(-) diff --git a/apps/trading/.env b/apps/trading/.env index 78e6de583..1e3dba3ca 100644 --- a/apps/trading/.env +++ b/apps/trading/.env @@ -1,27 +1,28 @@ +NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8 NX_ETHERSCAN_URL=https://sepolia.etherscan.io NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions NX_HOSTED_WALLET_URL=https://wallet.testnet.vega.xyz -NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json -NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/stagnet1/vegawallet-stagnet1.toml -NX_VEGA_ENV=STAGNET1 -NX_VEGA_EXPLORER_URL=https://explorer.stagnet1.vega.rocks +NX_SENTRY_DSN=https://2ffce43721964aafa78277c50654ece4@o286262.ingest.sentry.io/6300613 +NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/fairground/vegawallet-fairground.toml +NX_VEGA_ENV=TESTNET +NX_VEGA_EXPLORER_URL=https://explorer.fairground.wtf NX_VEGA_NETWORKS={\"MAINNET\":\"https://console.vega.xyz\",\"TESTNET\":\"https://console.fairground.wtf\",\"STAGNET1\":\"https://trading.stagnet1.vega.rocks\"} NX_VEGA_TOKEN_URL=https://governance.fairground.wtf NX_VEGA_WALLET_URL=http://localhost:1789 NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet NX_VEGA_REPO_URL=https://github.com/vegaprotocol/vega/releases -NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/main/announcements.json -NX_WALLETCONNECT_PROJECT_ID=fe8091dc35738863e509fc4947525c72 +NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json +NX_VEGA_INCIDENT_URL=https://blog.vega.xyz/tagged/vega-incident-reports +NX_VEGA_CONSOLE_URL=https://console.fairground.wtf NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/firefox/addon/vega-wallet-fairground - # Cosmic elevator flags NX_SUCCESSOR_MARKETS=true NX_STOP_ORDERS=true -# NX_ICEBERG_ORDERS +NX_ICEBERG_ORDERS=true # NX_PRODUCT_PERPETUALS -NX_METAMASK_SNAPS=true +NX_METAMASK_SNAPS=false -NX_TENDERMINT_URL=https://tm.n01.stagnet1.vega.rocks -NX_TENDERMINT_WEBSOCKET_URL=wss://tm.n01.stagnet1.vega.xyz/websocket +NX_TENDERMINT_URL=https://tm.be.testnet.vega.xyz +NX_TENDERMINT_WEBSOCKET_URL=wss://be.testnet.vega.xyz/websocket diff --git a/libs/deal-ticket/src/components/deal-ticket/deal-ticket-fee-details.tsx b/libs/deal-ticket/src/components/deal-ticket/deal-ticket-fee-details.tsx index 16c20a96a..74289f8b8 100644 --- a/libs/deal-ticket/src/components/deal-ticket/deal-ticket-fee-details.tsx +++ b/libs/deal-ticket/src/components/deal-ticket/deal-ticket-fee-details.tsx @@ -11,8 +11,7 @@ import { AccountBreakdownDialog } from '@vegaprotocol/accounts'; import { formatRange, formatValue } from '@vegaprotocol/utils'; import { marketMarginDataProvider } from '@vegaprotocol/accounts'; import { useDataProvider } from '@vegaprotocol/data-provider'; - -import * as Accordion from '@radix-ui/react-accordion'; +import * as AccordionPrimitive from '@radix-ui/react-accordion'; import { MARGIN_DIFF_TOOLTIP_TEXT, @@ -24,7 +23,13 @@ import { } from '../../constants'; import { useEstimateFees } from '../../hooks'; import { KeyValue } from './key-value'; -import { TOOLTIP_TRIGGER_CLASS_NAME } from '@vegaprotocol/ui-toolkit'; +import { + Accordion, + AccordionChevron, + AccordionPanel, + Tooltip, +} from '@vegaprotocol/ui-toolkit'; +import classNames from 'classnames'; const emptyValue = '-'; @@ -246,31 +251,56 @@ export const DealTicketMarginDetails = ({ const quoteName = market.tradableInstrument.instrument.product.quoteName; return ( - <> - - - - {t('Margin required')} - - } - value={formatRange( - marginRequiredBestCase, - marginRequiredWorstCase, - assetDecimals - )} - formattedValue={formatRange( - marginRequiredBestCase, - marginRequiredWorstCase, - assetDecimals, - quantum - )} - labelDescription={MARGIN_DIFF_TOOLTIP_TEXT(assetSymbol)} - symbol={assetSymbol} - /> - +
+ + +
+
+ + {t('Margin required')} + + + +
+ +
+ {formatRange( + marginRequiredBestCase, + marginRequiredWorstCase, + assetDecimals, + quantum + )}{' '} + {assetSymbol || ''} +
+
+
+ + } + > +
- - - +
+
+
{projectedMargin} )} - +
); }; diff --git a/libs/deal-ticket/src/components/deal-ticket/deal-ticket-stop-order.tsx b/libs/deal-ticket/src/components/deal-ticket/deal-ticket-stop-order.tsx index 8abb895bb..9daafbcb5 100644 --- a/libs/deal-ticket/src/components/deal-ticket/deal-ticket-stop-order.tsx +++ b/libs/deal-ticket/src/components/deal-ticket/deal-ticket-stop-order.tsx @@ -538,7 +538,7 @@ const NotionalAndFees = ({ market.positionDecimalPlaces ); return ( -
+
)} -
+
{ const displayValue = `${formattedValue ?? '-'} ${symbol || ''}`; const valueElement = onClick ? ( - ) : ( -
{displayValue}
+
{displayValue}
); return (
-
{label}
+
{label}
- + {valueElement}
diff --git a/libs/deal-ticket/src/constants.ts b/libs/deal-ticket/src/constants.ts index 1517df713..92c5c6bdf 100644 --- a/libs/deal-ticket/src/constants.ts +++ b/libs/deal-ticket/src/constants.ts @@ -8,7 +8,7 @@ export const EST_MARGIN_TOOLTIP_TEXT = (settlementAsset: string) => [settlementAsset] ); export const EST_TOTAL_MARGIN_TOOLTIP_TEXT = t( - 'Estimated total margin that will cover open position, active orders and this order.' + 'Estimated total margin that will cover open positions, active orders and this order.' ); export const MARGIN_ACCOUNT_TOOLTIP_TEXT = t('Margin account balance.'); export const MARGIN_DIFF_TOOLTIP_TEXT = (settlementAsset: string) => @@ -60,7 +60,7 @@ export const EST_FEES_TOOLTIP_TEXT = t( ); export const LIQUIDATION_PRICE_ESTIMATE_TOOLTIP_TEXT = t( - 'This is a approximation to the liquidation price for that particular contract position, assuming nothing else changes, which may affect your margin and collateral balances.' + 'This is an approximation (or a range) for the liquidation price for that particular contract position, assuming nothing else changes, which may affect your margin and collateral balances.' ); export const EST_SLIPPAGE = t( diff --git a/libs/ui-toolkit/src/components/accordion/accordion.tsx b/libs/ui-toolkit/src/components/accordion/accordion.tsx index 9e52f8250..190060525 100644 --- a/libs/ui-toolkit/src/components/accordion/accordion.tsx +++ b/libs/ui-toolkit/src/components/accordion/accordion.tsx @@ -1,5 +1,6 @@ import * as AccordionPrimitive from '@radix-ui/react-accordion'; import classNames from 'classnames'; +import type { VegaIconProps } from '../icon'; import { VegaIcon, VegaIconNames } from '../icon'; export interface AccordionItemProps { @@ -24,6 +25,28 @@ export const Accordion = ({ panels, children }: AccordionProps) => { ); }; +export const AccordionPanel = ({ + trigger, + children, + itemId, +}: { + trigger: React.ReactNode; + children: React.ReactNode; + itemId: string; +}) => { + return ( + + {trigger} + + {children} + + + ); +}; + export const AccordionItem = ({ title, content, @@ -31,7 +54,7 @@ export const AccordionItem = ({ }: AccordionPanelProps) => { const triggerClassNames = classNames( 'w-full py-2', - 'flex items-center justify-between border-b border-vega-light-200 dark:border-vega-dark-200 text-sm', + 'flex items-center justify-between gap-2 border-b border-vega-light-200 dark:border-vega-dark-200 text-sm', 'group' ); return ( @@ -41,7 +64,9 @@ export const AccordionItem = ({ data-testid="accordion-toggle" className={triggerClassNames} > - {title} + + {title} + @@ -55,15 +80,17 @@ export const AccordionItem = ({ ); }; -export const AccordionChevron = () => { +export const AccordionChevron = ({ + size = 16, +}: Pick) => { return ( - + ); }; diff --git a/libs/ui-toolkit/src/components/tooltip/tooltip.tsx b/libs/ui-toolkit/src/components/tooltip/tooltip.tsx index fdbae9814..1b3d8f30c 100644 --- a/libs/ui-toolkit/src/components/tooltip/tooltip.tsx +++ b/libs/ui-toolkit/src/components/tooltip/tooltip.tsx @@ -8,6 +8,7 @@ import { Portal, } from '@radix-ui/react-tooltip'; import type { ITooltipParams } from 'ag-grid-community'; +import classNames from 'classnames'; const tooltipContentClasses = 'max-w-sm bg-vega-light-100 dark:bg-vega-dark-100 border border-vega-light-200 dark:border-vega-dark-200 px-2 py-1 z-20 rounded text-xs text-black dark:text-white break-word'; @@ -18,10 +19,14 @@ export interface TooltipProps { align?: 'start' | 'center' | 'end'; side?: 'top' | 'right' | 'bottom' | 'left'; sideOffset?: number; + noUnderline?: boolean; } -export const TOOLTIP_TRIGGER_CLASS_NAME = - 'underline underline-offset-2 decoration-neutral-400 dark:decoration-neutral-400 decoration-dashed'; +export const TOOLTIP_TRIGGER_CLASS_NAME = (noUnderline?: boolean) => + classNames( + { 'underline underline-offset-2': !noUnderline }, + 'decoration-neutral-400 dark:decoration-neutral-400 decoration-dashed' + ); // Conditionally rendered tooltip if description content is provided. export const Tooltip = ({ @@ -31,11 +36,12 @@ export const Tooltip = ({ sideOffset, align = 'start', side = 'bottom', + noUnderline, }: TooltipProps) => description ? ( - + {children} {description && ( From c7d0803164137ce82d9281ae362df4afc65a65aa Mon Sep 17 00:00:00 2001 From: Matthew Russell Date: Tue, 12 Sep 2023 12:47:47 -0700 Subject: [PATCH 09/31] chore(trading): make closed market table rows the correct height --- apps/trading/client-pages/markets/closed.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/trading/client-pages/markets/closed.tsx b/apps/trading/client-pages/markets/closed.tsx index 152585663..03b49b31f 100644 --- a/apps/trading/client-pages/markets/closed.tsx +++ b/apps/trading/client-pages/markets/closed.tsx @@ -267,6 +267,7 @@ const ClosedMarketsDataGrid = ({ getRowId={({ data }) => data.id} overlayNoRowsTemplate={error ? error.message : t('No markets')} components={components} + rowHeight={45} /> ); }; From c6df34fe9501efdb953f56d8c6b96bb41be1c431 Mon Sep 17 00:00:00 2001 From: Matthew Russell Date: Tue, 12 Sep 2023 13:40:08 -0700 Subject: [PATCH 10/31] chore(trading): bump app version and enable snaps --- apps/trading/.env.mainnet | 4 ++-- apps/trading/.env.testnet | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/trading/.env.mainnet b/apps/trading/.env.mainnet index b02a11b93..d81fa2908 100644 --- a/apps/trading/.env.mainnet +++ b/apps/trading/.env.mainnet @@ -16,14 +16,14 @@ NX_VEGA_CONSOLE_URL=https://console.vega.xyz NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-mainnet/codfcglpplgmmlokgilfkpcjnmkbfiel NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/firefox/addon/vega-wallet-mainnet # TAG name of the current app version - TODO: bump to the latest upon release -NX_APP_VERSION=v0.21.0-core-0.72.14 +NX_APP_VERSION=v0.21.1-core-0.72.14 # Cosmic elevator flags NX_SUCCESSOR_MARKETS=true NX_STOP_ORDERS=true NX_ICEBERG_ORDERS=true # NX_PRODUCT_PERPETUALS -NX_METAMASK_SNAPS=false +NX_METAMASK_SNAPS=true NX_TENDERMINT_URL=https://be.vega.community NX_TENDERMINT_WEBSOCKET_URL=wss://be.vega.community/websocket diff --git a/apps/trading/.env.testnet b/apps/trading/.env.testnet index 1e3dba3ca..fb03c98f4 100644 --- a/apps/trading/.env.testnet +++ b/apps/trading/.env.testnet @@ -22,7 +22,7 @@ NX_SUCCESSOR_MARKETS=true NX_STOP_ORDERS=true NX_ICEBERG_ORDERS=true # NX_PRODUCT_PERPETUALS -NX_METAMASK_SNAPS=false +NX_METAMASK_SNAPS=true NX_TENDERMINT_URL=https://tm.be.testnet.vega.xyz NX_TENDERMINT_WEBSOCKET_URL=wss://be.testnet.vega.xyz/websocket From 86da521da5bb27b60e5b87078e1bf47136c6b439 Mon Sep 17 00:00:00 2001 From: Joe Tsang <30622993+jtsang586@users.noreply.github.com> Date: Wed, 13 Sep 2023 11:53:22 +0100 Subject: [PATCH 11/31] test(governance): flaky test fixes (#4760) --- .../src/integration/flow/staking-flow.cy.ts | 8 ++++---- apps/governance-e2e/src/support/staking.functions.ts | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/governance-e2e/src/integration/flow/staking-flow.cy.ts b/apps/governance-e2e/src/integration/flow/staking-flow.cy.ts index c5e67fd51..ef0160218 100644 --- a/apps/governance-e2e/src/integration/flow/staking-flow.cy.ts +++ b/apps/governance-e2e/src/integration/flow/staking-flow.cy.ts @@ -262,10 +262,10 @@ context( '2' ); waitForBeginningOfEpoch(); - cy.getByTestId(stakeValidatorListStakePercentage).should( - 'have.text', - '50.02%' - ); + cy.getByTestId( + stakeValidatorListStakePercentage, + epochTimeout + ).should('have.text', '50.02%'); navigateTo(navigation.validators); validateValidatorListTotalStakeAndShare('0', '3,002.00', '50.02%'); } diff --git a/apps/governance-e2e/src/support/staking.functions.ts b/apps/governance-e2e/src/support/staking.functions.ts index e8ad75851..51865bad1 100644 --- a/apps/governance-e2e/src/support/staking.functions.ts +++ b/apps/governance-e2e/src/support/staking.functions.ts @@ -170,21 +170,20 @@ export function clickOnValidatorFromList( validatorName = null ) { cy.contains('Loading...', epochTimeout).should('not.exist'); - waitForBeginningOfEpoch(); // below is to ensure validator list is shown cy.get(stakeValidatorListName, { timeout: 10000 }).should('exist'); cy.get(stakeValidatorListPendingStake, txTimeout).should( 'not.contain', '2,000,000,000,000,000,000.00' // number due to bug #936 ); + waitForBeginningOfEpoch(); if (validatorName) { cy.contains(validatorName).click(); } else { cy.get(`[row-id="${validatorNumber}"]`) .should('be.visible') .first() - .as('validatorOnList'); - cy.get('@validatorOnList').click(); + .click(); } } @@ -196,6 +195,7 @@ export function validateValidatorListTotalStakeAndShare( cy.contains('Loading...', epochTimeout).should('not.exist'); waitForBeginningOfEpoch(); cy.get(`[row-id="${positionOnList}"]`) + .should('have.length', 2) .eq(1) .within(() => { cy.getByTestId(stakeValidatorListTotalStake, epochTimeout).should( From aa38e0c001d652485f9279b20db05940d9c8dcf0 Mon Sep 17 00:00:00 2001 From: Joe Tsang <30622993+jtsang586@users.noreply.github.com> Date: Wed, 13 Sep 2023 13:02:47 +0100 Subject: [PATCH 12/31] test(governance): add assert for numerical sort (#4742) --- .../src/fixtures/mocks/network-upgrade.ts | 17 ++++++++++++++++- .../src/integration/view/proposal.cy.ts | 13 +++++++++++-- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/apps/governance-e2e/src/fixtures/mocks/network-upgrade.ts b/apps/governance-e2e/src/fixtures/mocks/network-upgrade.ts index 8aabb8974..2c229de58 100644 --- a/apps/governance-e2e/src/fixtures/mocks/network-upgrade.ts +++ b/apps/governance-e2e/src/fixtures/mocks/network-upgrade.ts @@ -19,7 +19,22 @@ export const upgradeProposalsData = { }, { node: { - upgradeBlockHeight: '1955065', + upgradeBlockHeight: '10001', + vegaReleaseTag: 'v0.71.0+dev-12156-bca1d57e', + approvers: [ + '02a6531716b7a6d82779b7793c3ad2fcb47290ea2ff0912c56f61219bd9675ff', + '121934387281812a2d5e6913e5d57c0f85a8f169e2752347ee2e23b52d46623c', + '65c80e2f5f84e2109eec30810f137ba04cbbecaba8f27706c146cc6c6f90db29', + 'bd6339d2428c79ac3bc9011771236d17bac92bcb1806423388d52fb440043aef', + ], + status: 'PROTOCOL_UPGRADE_PROPOSAL_STATUS_APPROVED', + __typename: 'ProtocolUpgradeProposal', + }, + __typename: 'ProtocolUpgradeProposalEdge', + }, + { + node: { + upgradeBlockHeight: '20', vegaReleaseTag: 'v0.71.0+dev-12156-bca1d57e', approvers: [ '02a6531716b7a6d82779b7793c3ad2fcb47290ea2ff0912c56f61219bd9675ff', diff --git a/apps/governance-e2e/src/integration/view/proposal.cy.ts b/apps/governance-e2e/src/integration/view/proposal.cy.ts index 0c98565a3..d81460944 100644 --- a/apps/governance-e2e/src/integration/view/proposal.cy.ts +++ b/apps/governance-e2e/src/integration/view/proposal.cy.ts @@ -15,6 +15,7 @@ const proposalDocumentationLink = 'proposal-documentation-link'; const connectToVegaWalletButton = 'connect-to-vega-wallet-btn'; const governanceDocsUrl = 'https://vega.xyz/governance'; const networkUpgradeProposalListItem = 'protocol-upgrade-proposals-list-item'; +const proposalUpgradeBlockHeight = 'protocol-upgrade-proposal-block-height'; const closedProposals = 'closed-proposals'; const closedProposalToggle = 'closed-proposals-toggle-networkUpgrades'; const protocolUpgradeTime = 'protocol-upgrade-time'; @@ -184,7 +185,7 @@ context( 'have.text', 'Vega release tag: v1' ); - cy.getByTestId('protocol-upgrade-proposal-block-height').should( + cy.getByTestId(proposalUpgradeBlockHeight).should( 'have.text', 'Upgrade block height: 2015942' ); @@ -199,7 +200,15 @@ context( }); cy.getByTestId(closedProposalToggle).click(); cy.getByTestId(closedProposals).within(() => { - cy.getByTestId(networkUpgradeProposalListItem).should('have.length', 1); + cy.getByTestId(networkUpgradeProposalListItem).should('have.length', 2); + cy.getByTestId(networkUpgradeProposalListItem) + .first() + .within(() => { + cy.getByTestId(proposalUpgradeBlockHeight).should( + 'contain.text', + '10001' + ); + }); }); }); From e3a00ada05a06e2bf83c34629970dc1c896b1088 Mon Sep 17 00:00:00 2001 From: Matthew Russell Date: Wed, 13 Sep 2023 08:30:06 -0700 Subject: [PATCH 13/31] chore(trading,governance,explorer): update pr template to ensure issues get linked --- .github/PULL_REQUEST_TEMPLATE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index ac7391e1d..ba9852abb 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,6 +1,6 @@ # Related issues 🔗 -Issue: #[Issue number here] +Closes #[Issue number here] # Description ℹ️ From c433a4ee0632b445547d55a3d1764ba83fb33d20 Mon Sep 17 00:00:00 2001 From: Sam Keen Date: Wed, 13 Sep 2023 19:01:33 +0100 Subject: [PATCH 14/31] feat(governance): more mobile view improvements (#4751) Co-authored-by: Joe --- .../src/support/staking.functions.ts | 3 +- apps/governance/src/routes/home/index.tsx | 2 +- .../components/proposal/proposal.tsx | 2 +- .../consensus-validators-table.tsx | 2 - .../standby-pending-validators-table.tsx | 2 - .../routes/staking/node/validator-table.tsx | 315 +++++++++--------- .../token/token-details/token-details.tsx | 2 +- 7 files changed, 169 insertions(+), 159 deletions(-) diff --git a/apps/governance-e2e/src/support/staking.functions.ts b/apps/governance-e2e/src/support/staking.functions.ts index 51865bad1..73802df1b 100644 --- a/apps/governance-e2e/src/support/staking.functions.ts +++ b/apps/governance-e2e/src/support/staking.functions.ts @@ -195,8 +195,7 @@ export function validateValidatorListTotalStakeAndShare( cy.contains('Loading...', epochTimeout).should('not.exist'); waitForBeginningOfEpoch(); cy.get(`[row-id="${positionOnList}"]`) - .should('have.length', 2) - .eq(1) + .first() .within(() => { cy.getByTestId(stakeValidatorListTotalStake, epochTimeout).should( 'have.text', diff --git a/apps/governance/src/routes/home/index.tsx b/apps/governance/src/routes/home/index.tsx index 3d098cc9a..a2ae40d6a 100644 --- a/apps/governance/src/routes/home/index.tsx +++ b/apps/governance/src/routes/home/index.tsx @@ -45,7 +45,7 @@ const HomeProposals = ({ const { t } = useTranslation(); return ( -
+

{t('homeProposalsIntro')}

diff --git a/apps/governance/src/routes/proposals/components/proposal/proposal.tsx b/apps/governance/src/routes/proposals/components/proposal/proposal.tsx index ebd3b0da7..327d84cfe 100644 --- a/apps/governance/src/routes/proposals/components/proposal/proposal.tsx +++ b/apps/governance/src/routes/proposals/components/proposal/proposal.tsx @@ -127,7 +127,7 @@ export const Proposal = ({ voteState={voteState} /> -
+
diff --git a/apps/governance/src/routes/staking/home/validator-tables/consensus-validators-table.tsx b/apps/governance/src/routes/staking/home/validator-tables/consensus-validators-table.tsx index cb25126fc..b9b42cad3 100644 --- a/apps/governance/src/routes/staking/home/validator-tables/consensus-validators-table.tsx +++ b/apps/governance/src/routes/staking/home/validator-tables/consensus-validators-table.tsx @@ -352,7 +352,6 @@ export const ConsensusValidatorsTable = ({ field: ValidatorFields.RANKING_INDEX, headerName: '#', width: 60, - pinned: 'left', }, { field: ValidatorFields.VALIDATOR, @@ -362,7 +361,6 @@ export const ConsensusValidatorsTable = ({ if (a === b) return 0; return a > b ? 1 : -1; }, - pinned: 'left', width: 260, }, { diff --git a/apps/governance/src/routes/staking/home/validator-tables/standby-pending-validators-table.tsx b/apps/governance/src/routes/staking/home/validator-tables/standby-pending-validators-table.tsx index c3a1d55ef..f1553756a 100644 --- a/apps/governance/src/routes/staking/home/validator-tables/standby-pending-validators-table.tsx +++ b/apps/governance/src/routes/staking/home/validator-tables/standby-pending-validators-table.tsx @@ -195,14 +195,12 @@ export const StandbyPendingValidatorsTable = ({ field: ValidatorFields.RANKING_INDEX, headerName: '#', width: 60, - pinned: 'left', }, { field: ValidatorFields.VALIDATOR, headerName: t(ValidatorFields.VALIDATOR).toString(), cellRenderer: ValidatorRenderer, comparator: ({ name: a }, { name: b }) => Math.sign(a - b), - pinned: 'left', width: 260, }, { diff --git a/apps/governance/src/routes/staking/node/validator-table.tsx b/apps/governance/src/routes/staking/node/validator-table.tsx index dcec7bb68..a91ab84e9 100644 --- a/apps/governance/src/routes/staking/node/validator-table.tsx +++ b/apps/governance/src/routes/staking/node/validator-table.tsx @@ -122,38 +122,43 @@ export const ValidatorTable = ({
- - - - {t('id')} - - {node.id} - - - - {t('ABOUT THIS VALIDATOR')} +
+ + + + {t('id')} + + {node.id} + + + + {t('ABOUT THIS VALIDATOR')} - - - {node.infoUrl} - - - - - - {t('STATUS')} - - - - - - {t(statusTranslationKey(node.rankingScore.status))} - + + + {node.infoUrl} + + + + + + {t('STATUS')} - - - - + + + + + {t(statusTranslationKey(node.rankingScore.status))} + + + + + + +
{t('validatorTableIntro')}{' '} @@ -167,144 +172,154 @@ export const ValidatorTable = ({
- - - - {t('VEGA ADDRESS / PUBLIC KEY')} - - {node.pubkey} - - - - {t('SERVER LOCATION')} - - {countryData.find((c) => c.code === node.location)?.name || - t('not available')} - - - - {t('ETHEREUM ADDRESS')} - - - {node.ethereumAddress} - - - - - +
+ + + + {t('VEGA ADDRESS / PUBLIC KEY')} + + {node.pubkey} + + + + {t('SERVER LOCATION')} + + {countryData.find((c) => c.code === node.location)?.name || + t('not available')} + + + + {t('ETHEREUM ADDRESS')} + + + {node.ethereumAddress} + + + + + +
- - - - {t('STAKED BY OPERATOR')} +
+ + + + {t('STAKED BY OPERATOR')} - - - {formatNumber(toBigNum(node.stakedByOperator, decimals))} + + + {formatNumber(toBigNum(node.stakedByOperator, decimals))} + + + + + {t('STAKED BY DELEGATES')} + + + + {formatNumber(toBigNum(node.stakedByDelegates, decimals))} + + + + + + {t('TOTAL STAKE')} - - - - {t('STAKED BY DELEGATES')} - - - {formatNumber(toBigNum(node.stakedByDelegates, decimals))} + + + {formatNumber(toBigNum(node.stakedTotal, decimals))} + - - - - - {t('TOTAL STAKE')} - + + + {t('PENDING STAKE')} - - - {formatNumber(toBigNum(node.stakedTotal, decimals))} - - - - - {t('PENDING STAKE')} + + + {formatNumber(toBigNum(node.pendingStake, decimals))} + + + + + {t('STAKE SHARE')} - - - {formatNumber(toBigNum(node.pendingStake, decimals))} - - - - - {t('STAKE SHARE')} - - - {stakePercentage} - - - - + + {stakePercentage} + + + + +
- - - - {t('OVERSTAKED PENALTY')} +
+ + + + {t('OVERSTAKED PENALTY')} - - - {formatNumberPercentage(penalties.overstaked, 2)} - - - - - {t('PERFORMANCE PENALTY')} + + + {formatNumberPercentage(penalties.overstaked, 2)} + + + + + {t('PERFORMANCE PENALTY')} - - - {formatNumberPercentage(penalties.performance, 2)} + + + {formatNumberPercentage(penalties.performance, 2)} + + + + + + {t('TOTAL PENALTIES')} - - - - - {t('TOTAL PENALTIES')} - - - {formatNumberPercentage(penalties.overall, 2)} - - - - + + + {formatNumberPercentage(penalties.overall, 2)} + + + + + +
- - - - {t('UNNORMALISED VOTING POWER')} +
+ + + + {t('UNNORMALISED VOTING POWER')} - - - {getUnnormalisedVotingPower(rawValidatorScore)} + + + {getUnnormalisedVotingPower(rawValidatorScore)} + + + + + + {t('NORMALISED VOTING POWER')} - - - - - {t('NORMALISED VOTING POWER')} - - - - {getNormalisedVotingPower(node.rankingScore.votingPower)} - - - - - + + + {getNormalisedVotingPower(node.rankingScore.votingPower)} + + + + + +
); diff --git a/apps/governance/src/routes/token/token-details/token-details.tsx b/apps/governance/src/routes/token/token-details/token-details.tsx index 7472c48e1..1012106c4 100644 --- a/apps/governance/src/routes/token/token-details/token-details.tsx +++ b/apps/governance/src/routes/token/token-details/token-details.tsx @@ -54,7 +54,7 @@ export const TokenDetails = ({ config.token_vesting_contract?.address || ENV.addresses.tokenVestingAddress; return ( -
+
From af6719cc9dc77f6eeced629b98526ba3e9fd9d7d Mon Sep 17 00:00:00 2001 From: "m.ray" <16125548+MadalinaRaicu@users.noreply.github.com> Date: Thu, 14 Sep 2023 00:25:31 +0300 Subject: [PATCH 15/31] chore(trading): add governance link to top level nav (#4765) Co-authored-by: Matthew Russell --- .../trading/components/navbar/navbar.spec.tsx | 2 ++ apps/trading/components/navbar/navbar.tsx | 29 +++++++++++++------ 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/apps/trading/components/navbar/navbar.spec.tsx b/apps/trading/components/navbar/navbar.spec.tsx index cb8d40a87..941f8f140 100644 --- a/apps/trading/components/navbar/navbar.spec.tsx +++ b/apps/trading/components/navbar/navbar.spec.tsx @@ -57,6 +57,7 @@ describe('Navbar', () => { ['/markets/all', 'Markets'], [`/markets/${marketId}`, 'Trading'], ['/portfolio', 'Portfolio'], + [expect.stringContaining('governance'), 'Governance'], ]; const links = screen.getAllByRole('link'); @@ -88,6 +89,7 @@ describe('Navbar', () => { ['/markets/all', 'Markets'], [`/markets/${marketId}`, 'Trading'], ['/portfolio', 'Portfolio'], + [expect.stringContaining('governance'), 'Governance'], ]; const links = menu.getAllByRole('link'); links.forEach((link, i) => { diff --git a/apps/trading/components/navbar/navbar.tsx b/apps/trading/components/navbar/navbar.tsx index 4d27ed3f6..904ea9e68 100644 --- a/apps/trading/components/navbar/navbar.tsx +++ b/apps/trading/components/navbar/navbar.tsx @@ -1,6 +1,12 @@ import type { ButtonHTMLAttributes, LiHTMLAttributes, ReactNode } from 'react'; import { useState } from 'react'; -import { useEnvironment, DocsLinks, Networks } from '@vegaprotocol/environment'; +import { + useEnvironment, + DocsLinks, + Networks, + DApp, + useLinks, +} from '@vegaprotocol/environment'; import { t } from '@vegaprotocol/i18n'; import { useGlobalStore } from '../../stores'; import { VegaWalletConnectButton } from '../vega-wallet-connect-button'; @@ -59,14 +65,14 @@ export const Navbar = ({ {/* Left section */} -
{children}
+
{children}
{/* Used to show header in nav on mobile */}
setMenu(null)} />
{/* Right section */} -
+
{ @@ -100,7 +106,7 @@ export const Navbar = ({ onOpenChange={(open) => setMenu((x) => (open ? x : null))} > -
+
setMenu(null)}> {t('Close menu')} @@ -179,6 +185,11 @@ const NavbarMenu = ({ onClick }: { onClick: () => void }) => { {t('Portfolio')} + + + {t('Governance')} + + {t('Resources')} @@ -336,7 +347,7 @@ const NavbarLinkExternal = ({ {children} - + ); @@ -364,8 +375,8 @@ const BurgerIcon = () => ( const NavbarListDivider = () => { return ( -
-
+
+
); }; From fbd01dc1bd50b3e63621becd228e8a02cbe3b724 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20G=C5=82ownia?= Date: Thu, 14 Sep 2023 20:18:58 +0200 Subject: [PATCH 16/31] fix(trading): use asset decimals to format liquidation price in posions table (#4787) Co-authored-by: Matthew Russell --- .../deal-ticket-stop-order.spec.tsx | 3 +++ libs/positions/src/lib/liquidation-price.tsx | 20 +++++++++++++------ libs/positions/src/lib/positions-table.tsx | 6 +++++- 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/libs/deal-ticket/src/components/deal-ticket/deal-ticket-stop-order.spec.tsx b/libs/deal-ticket/src/components/deal-ticket/deal-ticket-stop-order.spec.tsx index bdaaf081e..a4c7d1054 100644 --- a/libs/deal-ticket/src/components/deal-ticket/deal-ticket-stop-order.spec.tsx +++ b/libs/deal-ticket/src/components/deal-ticket/deal-ticket-stop-order.spec.tsx @@ -84,6 +84,7 @@ const ocoPostfix = (id: string, postfix = true) => (postfix ? `${id}-oco` : id); const mockDataProvider = jest.fn((...args) => ({ data: Array(0), + reload: jest.fn(), })); jest.mock('@vegaprotocol/data-provider', () => ({ ...jest.requireActual('@vegaprotocol/data-provider'), @@ -473,6 +474,7 @@ describe('StopOrder', () => { it('shows limit of active stop orders number', async () => { mockDataProvider.mockReturnValue({ + reload: jest.fn(), data: Array(4), }); render(generateJsx()); @@ -484,6 +486,7 @@ describe('StopOrder', () => { it('counts oco as two orders', async () => { mockDataProvider.mockReturnValue({ + reload: jest.fn(), data: Array(3), }); render(generateJsx()); diff --git a/libs/positions/src/lib/liquidation-price.tsx b/libs/positions/src/lib/liquidation-price.tsx index f5afd0ccb..283dc6d6a 100644 --- a/libs/positions/src/lib/liquidation-price.tsx +++ b/libs/positions/src/lib/liquidation-price.tsx @@ -7,13 +7,21 @@ export const LiquidationPrice = ({ marketId, openVolume, collateralAvailable, - marketDecimalPlaces, + decimalPlaces, + formatDecimals, }: { marketId: string; openVolume: string; collateralAvailable: string; - marketDecimalPlaces: number; + decimalPlaces: number; + formatDecimals: number; }) => { + // NOTE! + // + // The estimate order query API gives us the liquidation price unformatted but expecting to be converted + // using asset decimal placse. + // + // We need to convert it with asset decimals, but display it formatted with market decimals precision until the API changes. const { data: currentData, previousData } = useEstimatePositionQuery({ variables: { marketId, @@ -43,8 +51,8 @@ export const LiquidationPrice = ({ /\..*/, '' ); - worstCase = addDecimalsFormatNumber(worstCase, marketDecimalPlaces); - bestCase = addDecimalsFormatNumber(bestCase, marketDecimalPlaces); + worstCase = addDecimalsFormatNumber(worstCase, decimalPlaces, formatDecimals); + bestCase = addDecimalsFormatNumber(bestCase, decimalPlaces, formatDecimals); return ( {t('Worst case')} - {worstCase} + {worstCase} {t('Best case')} - {bestCase} + {bestCase} diff --git a/libs/positions/src/lib/positions-table.tsx b/libs/positions/src/lib/positions-table.tsx index 8d7d5a652..27804419c 100644 --- a/libs/positions/src/lib/positions-table.tsx +++ b/libs/positions/src/lib/positions-table.tsx @@ -339,12 +339,16 @@ export const PositionsTable = ({ if (!data) { return '-'; } + // The estimate order query API gives us the liquidation price unformatted but expecting + // conversion using asset decimals. We need to convert it with asset decimals, but format + // it with market decimals precision until the API changes. return ( ); }, From e3c6dd41c946bf6891d8ac3395c4bf390bb2d4c9 Mon Sep 17 00:00:00 2001 From: Matthew Russell Date: Thu, 14 Sep 2023 12:10:33 -0700 Subject: [PATCH 17/31] fix(trading): simplify onboarding and explore button to use top traded (#4781) --- apps/trading/client-pages/home/home.tsx | 25 ++-- apps/trading/components/constants.ts | 1 - apps/trading/components/telemetry/index.ts | 1 + .../telemetry-approval.spec.tsx | 0 .../telemetry-approval.tsx | 0 .../components/telemetry/telemetry.tsx | 69 +++++++++ .../welcome-dialog/get-started.spec.tsx | 9 +- .../components/welcome-dialog/get-started.tsx | 28 ++-- .../welcome-dialog/use-get-onboarding-step.ts | 25 ++++ .../welcome-dialog/welcome-dialog-content.tsx | 57 +++----- .../welcome-dialog/welcome-dialog.tsx | 133 +++--------------- .../lib/hooks/use-top-traded-markets.tsx | 13 ++ apps/trading/pages/_app.page.tsx | 2 + .../src/lib/commands/vega-wallet-connect.ts | 12 +- .../vega-icons/svg-icons/icon-eye-off.tsx | 3 +- .../trading-button/trading-button.tsx | 45 +++--- 16 files changed, 204 insertions(+), 219 deletions(-) create mode 100644 apps/trading/components/telemetry/index.ts rename apps/trading/components/{welcome-dialog => telemetry}/telemetry-approval.spec.tsx (100%) rename apps/trading/components/{welcome-dialog => telemetry}/telemetry-approval.tsx (100%) create mode 100644 apps/trading/components/telemetry/telemetry.tsx create mode 100644 apps/trading/lib/hooks/use-top-traded-markets.tsx diff --git a/apps/trading/client-pages/home/home.tsx b/apps/trading/client-pages/home/home.tsx index 7d0b48cf2..c4974bc99 100644 --- a/apps/trading/client-pages/home/home.tsx +++ b/apps/trading/client-pages/home/home.tsx @@ -1,20 +1,16 @@ import { useEffect } from 'react'; import { useNavigate } from 'react-router-dom'; -import { marketsWithDataProvider } from '@vegaprotocol/markets'; -import { useDataProvider } from '@vegaprotocol/data-provider'; -import { AsyncRenderer } from '@vegaprotocol/ui-toolkit'; +import { Loader, Splash } from '@vegaprotocol/ui-toolkit'; import { Links, Routes } from '../../pages/client-router'; import { useGlobalStore } from '../../stores'; +import { useTopTradedMarkets } from '../../lib/hooks/use-top-traded-markets'; +// The home pages only purpose is to redirect to the users last market, +// the top traded if they are new, or fall back to the list of markets. +// Thats why we just render a loader here export const Home = () => { const navigate = useNavigate(); - // The default market selected in the platform behind the overlay - // should be the oldest market that is currently trading in continuous mode(i.e. not in auction). - const { data, error, loading } = useDataProvider({ - dataProvider: marketsWithDataProvider, - variables: undefined, - }); - const update = useGlobalStore((store) => store.update); + const { data } = useTopTradedMarkets(); const marketId = useGlobalStore((store) => store.marketId); useEffect(() => { @@ -32,12 +28,11 @@ export const Home = () => { navigate(Links[Routes.MARKETS]()); } } - }, [marketId, data, navigate, update]); + }, [marketId, data, navigate]); return ( - - {/* Render a loading and error state but we will redirect if markets are found */} - {null} - + + + ); }; diff --git a/apps/trading/components/constants.ts b/apps/trading/components/constants.ts index 4e9781d22..b157c3b5f 100644 --- a/apps/trading/components/constants.ts +++ b/apps/trading/components/constants.ts @@ -1,2 +1 @@ export const THROTTLE_UPDATE_TIME = 500; -export const ONBOARDING_VIEWED_KEY = 'vega_onboarding_viewed'; diff --git a/apps/trading/components/telemetry/index.ts b/apps/trading/components/telemetry/index.ts new file mode 100644 index 000000000..a790051f1 --- /dev/null +++ b/apps/trading/components/telemetry/index.ts @@ -0,0 +1 @@ +export { Telemetry } from './telemetry'; diff --git a/apps/trading/components/welcome-dialog/telemetry-approval.spec.tsx b/apps/trading/components/telemetry/telemetry-approval.spec.tsx similarity index 100% rename from apps/trading/components/welcome-dialog/telemetry-approval.spec.tsx rename to apps/trading/components/telemetry/telemetry-approval.spec.tsx diff --git a/apps/trading/components/welcome-dialog/telemetry-approval.tsx b/apps/trading/components/telemetry/telemetry-approval.tsx similarity index 100% rename from apps/trading/components/welcome-dialog/telemetry-approval.tsx rename to apps/trading/components/telemetry/telemetry-approval.tsx diff --git a/apps/trading/components/telemetry/telemetry.tsx b/apps/trading/components/telemetry/telemetry.tsx new file mode 100644 index 000000000..e40a5e2d3 --- /dev/null +++ b/apps/trading/components/telemetry/telemetry.tsx @@ -0,0 +1,69 @@ +import type { Toast } from '@vegaprotocol/ui-toolkit'; +import { Intent, useToasts } from '@vegaprotocol/ui-toolkit'; +import { useTelemetryApproval } from '../../lib/hooks/use-telemetry-approval'; +import { useCallback, useEffect } from 'react'; +import { TelemetryApproval } from './telemetry-approval'; +import { t } from '@vegaprotocol/i18n'; +import { useOnboardingStore } from '../welcome-dialog/use-get-onboarding-step'; + +const TELEMETRY_APPROVAL_TOAST_ID = 'telemetry_tost_id'; + +export const Telemetry = () => { + const onboardingDissmissed = useOnboardingStore((store) => store.dismissed); + const [telemetryValue, setTelemetryValue, isTelemetryNeeded, closeTelemetry] = + useTelemetryApproval(); + + const [setToast, hasToast, removeToast] = useToasts((store) => [ + store.setToast, + store.hasToast, + store.remove, + ]); + + const onApprovalClose = useCallback(() => { + closeTelemetry(); + removeToast(TELEMETRY_APPROVAL_TOAST_ID); + }, [closeTelemetry, removeToast]); + + const setTelemetryApprovalAndClose = useCallback( + (value: string) => { + setTelemetryValue(value); + onApprovalClose(); + }, + [onApprovalClose, setTelemetryValue] + ); + + useEffect(() => { + if (isTelemetryNeeded && onboardingDissmissed) { + const toast: Toast = { + id: TELEMETRY_APPROVAL_TOAST_ID, + intent: Intent.Primary, + content: ( + <> +

+ {t('Improve vega console')} +

+ + + ), + onClose: onApprovalClose, + }; + if (!hasToast(TELEMETRY_APPROVAL_TOAST_ID)) { + setToast(toast); + } + return; + } + }, [ + telemetryValue, + isTelemetryNeeded, + onboardingDissmissed, + setToast, + hasToast, + onApprovalClose, + setTelemetryApprovalAndClose, + ]); + + return null; +}; diff --git a/apps/trading/components/welcome-dialog/get-started.spec.tsx b/apps/trading/components/welcome-dialog/get-started.spec.tsx index 3f5c12462..e0f805e33 100644 --- a/apps/trading/components/welcome-dialog/get-started.spec.tsx +++ b/apps/trading/components/welcome-dialog/get-started.spec.tsx @@ -2,7 +2,8 @@ import { MemoryRouter } from 'react-router-dom'; import type { VegaWalletContextShape } from '@vegaprotocol/wallet'; import { VegaWalletContext } from '@vegaprotocol/wallet'; import { GetStarted } from './get-started'; -import { render, screen } from '@testing-library/react'; +import { render, screen, fireEvent } from '@testing-library/react'; +import { useOnboardingStore } from './use-get-onboarding-step'; let mockStep = 1; jest.mock('./use-get-onboarding-step', () => ({ @@ -44,13 +45,15 @@ describe('GetStarted', () => { globalThis.window.vega = undefined as unknown as Vega; }); - it('renders nothing if connected', () => { + it('renders nothing if dismissed', () => { + useOnboardingStore.setState({ dismissed: true }); mockStep = 0; const { container } = renderComponent({ pubKey: 'my-pubkey' }); expect(container).toBeEmptyDOMElement(); }); it('steps should be ticked', () => { + useOnboardingStore.setState({ dismissed: false }); const navigatorGetter: jest.SpyInstance = jest.spyOn( window.navigator, 'userAgent', @@ -87,6 +90,8 @@ describe('GetStarted', () => { screen.getByRole('button', { name: 'Ready to trade' }) ).toBeInTheDocument(); + fireEvent.click(screen.getByRole('button', { name: 'Ready to trade' })); + mockStep = 5; rerender( diff --git a/apps/trading/components/welcome-dialog/get-started.tsx b/apps/trading/components/welcome-dialog/get-started.tsx index 086fdc58e..c496a5f55 100644 --- a/apps/trading/components/welcome-dialog/get-started.tsx +++ b/apps/trading/components/welcome-dialog/get-started.tsx @@ -9,17 +9,15 @@ import { } from '@vegaprotocol/ui-toolkit'; import { useVegaWallet, useVegaWalletDialogStore } from '@vegaprotocol/wallet'; import { Networks, useEnvironment } from '@vegaprotocol/environment'; -import { useLocalStorage } from '@vegaprotocol/react-helpers'; import { useNavigate } from 'react-router-dom'; import { OnboardingStep, useGetOnboardingStep, + useOnboardingStore, } from './use-get-onboarding-step'; import { Links, Routes } from '../../pages/client-router'; import { useGlobalStore } from '../../stores'; import { useSidebar, ViewType } from '../sidebar'; -import * as constants from '../constants'; -import { useOnboardingStore } from './welcome-dialog'; interface Props { lead?: string; @@ -27,11 +25,8 @@ interface Props { const GetStartedButton = ({ step }: { step: OnboardingStep }) => { const navigate = useNavigate(); - const [, setOnboardingViewed] = useLocalStorage( - constants.ONBOARDING_VIEWED_KEY - ); - const dismiss = useOnboardingStore((store) => store.dismiss); + const setDialogOpen = useOnboardingStore((store) => store.setDialogOpen); const marketId = useGlobalStore((store) => store.marketId); const link = marketId ? Links[Routes.MARKET](marketId) : Links[Routes.HOME](); const openVegaWalletDialog = useVegaWalletDialogStore( @@ -49,14 +44,14 @@ const GetStartedButton = ({ step }: { step: OnboardingStep }) => { onClickHandle = () => { navigate(link); setView({ type: ViewType.Deposit }); - dismiss(); + setDialogOpen(false); }; - } else if (step === OnboardingStep.ONBOARDING_ORDER_STEP) { + } else if (step >= OnboardingStep.ONBOARDING_ORDER_STEP) { buttonText = t('Ready to trade'); onClickHandle = () => { navigate(link); setView({ type: ViewType.Order }); - setOnboardingViewed('true'); + dismiss(); }; } @@ -75,17 +70,12 @@ const GetStartedButton = ({ step }: { step: OnboardingStep }) => { export const GetStarted = ({ lead }: Props) => { const { pubKey } = useVegaWallet(); const { VEGA_ENV, VEGA_NETWORKS } = useEnvironment(); - const CANONICAL_URL = VEGA_NETWORKS[VEGA_ENV] || 'https://console.vega.xyz'; - const [onBoardingViewed] = useLocalStorage(constants.ONBOARDING_VIEWED_KEY); - const currentStep = useGetOnboardingStep(); const openVegaWalletDialog = useVegaWalletDialogStore( (store) => store.openVegaWalletDialog ); - - const getStartedNeeded = - onBoardingViewed !== 'true' && - currentStep && - currentStep < OnboardingStep.ONBOARDING_COMPLETE_STEP; + const CANONICAL_URL = VEGA_NETWORKS[VEGA_ENV] || 'https://console.vega.xyz'; + const currentStep = useGetOnboardingStep(); + const dismissed = useOnboardingStore((store) => store.dismissed); const wrapperClasses = classNames( 'flex flex-col py-4 px-6 gap-4 rounded', @@ -94,7 +84,7 @@ export const GetStarted = ({ lead }: Props) => { { 'mt-8': !lead } ); - if (getStartedNeeded) { + if (!dismissed) { return (
{lead &&

{lead}

} diff --git a/apps/trading/components/welcome-dialog/use-get-onboarding-step.ts b/apps/trading/components/welcome-dialog/use-get-onboarding-step.ts index 66adb9553..3f90fa82b 100644 --- a/apps/trading/components/welcome-dialog/use-get-onboarding-step.ts +++ b/apps/trading/components/welcome-dialog/use-get-onboarding-step.ts @@ -1,3 +1,5 @@ +import { create } from 'zustand'; +import { persist } from 'zustand/middleware'; import { useVegaWallet } from '@vegaprotocol/wallet'; import { depositsProvider } from '@vegaprotocol/deposits'; import { useDataProvider } from '@vegaprotocol/data-provider'; @@ -7,6 +9,29 @@ import { aggregatedAccountsDataProvider } from '@vegaprotocol/accounts'; import { positionsDataProvider } from '@vegaprotocol/positions'; import { useGlobalStore } from '../../stores'; +const ONBOARDING_STORAGE_KEY = 'vega_onboarding'; +export const useOnboardingStore = create<{ + dialogOpen: boolean; + dismissed: boolean; + dismiss: () => void; + setDialogOpen: (isOpen: boolean) => void; +}>()( + persist( + (set) => ({ + dialogOpen: true, + dismissed: false, + dismiss: () => set({ dismissed: true }), + setDialogOpen: (isOpen) => set({ dialogOpen: isOpen }), + }), + { + name: ONBOARDING_STORAGE_KEY, + partialize: (state) => ({ + dismissed: state.dismissed, + }), + } + ) +); + export enum OnboardingStep { ONBOARDING_UNKNOWN_STEP, ONBOARDING_WALLET_STEP, diff --git a/apps/trading/components/welcome-dialog/welcome-dialog-content.tsx b/apps/trading/components/welcome-dialog/welcome-dialog-content.tsx index 1a2cedff6..f15471cff 100644 --- a/apps/trading/components/welcome-dialog/welcome-dialog-content.tsx +++ b/apps/trading/components/welcome-dialog/welcome-dialog-content.tsx @@ -1,40 +1,24 @@ import { t } from '@vegaprotocol/i18n'; import { GetStarted } from './get-started'; -import { TradingButton } from '@vegaprotocol/ui-toolkit'; -import { useNavigate } from 'react-router-dom'; +import { TradingAnchorButton } from '@vegaprotocol/ui-toolkit'; import { Links, Routes } from '../../pages/client-router'; import { Networks, useEnvironment } from '@vegaprotocol/environment'; import type { ReactNode } from 'react'; -import { useOnboardingStore } from './welcome-dialog'; -import { useMarketList } from '@vegaprotocol/markets'; -import { isMarketActive } from '../../lib/utils'; -import orderBy from 'lodash/orderBy'; -import { priceChangePercentage } from '@vegaprotocol/utils'; +import { useTopTradedMarkets } from '../../lib/hooks/use-top-traded-markets'; +import { useOnboardingStore } from './use-get-onboarding-step'; export const WelcomeDialogContent = () => { const { VEGA_ENV } = useEnvironment(); - - const dismiss = useOnboardingStore((store) => store.dismiss); - const navigate = useNavigate(); - const { data } = useMarketList(); - const markets = orderBy( - data?.filter((m) => isMarketActive(m.state)) || [], - [ - (m) => { - if (!m.candles?.length) return 0; - return Number(priceChangePercentage(m.candles.map((c) => c.close))); - }, - ], - ['desc'] + const setOnboardingDialog = useOnboardingStore( + (store) => store.setDialogOpen ); - const explore = () => { - const marketId = markets?.[0].id ?? ''; - const link = marketId - ? Links[Routes.MARKET](marketId) - : Links[Routes.MARKETS](); - navigate(link); - dismiss(); - }; + + const { data } = useTopTradedMarkets(); + const marketId = data && data[0]?.id; + const link = marketId + ? Links[Routes.MARKET](marketId) + : Links[Routes.MARKETS](); + const lead = VEGA_ENV === Networks.MAINNET ? t('Start trading on the worlds most advanced decentralised exchange.') @@ -43,7 +27,7 @@ export const WelcomeDialogContent = () => { ); return (
-
+
    } @@ -65,15 +49,16 @@ export const WelcomeDialogContent = () => { )} />
- setOnboardingDialog(false)} className="block w-full" data-testid="browse-markets-button" > {t('Explore')} - +
-
+
@@ -90,10 +75,10 @@ const ListItemContent = ({ text: string; }) => { return ( -
  • -
    {icon}
    +
  • +
    {icon}
    -

    {title}

    +

    {title}

    {text}

  • diff --git a/apps/trading/components/welcome-dialog/welcome-dialog.tsx b/apps/trading/components/welcome-dialog/welcome-dialog.tsx index 7f7cbb06e..0e40e7333 100644 --- a/apps/trading/components/welcome-dialog/welcome-dialog.tsx +++ b/apps/trading/components/welcome-dialog/welcome-dialog.tsx @@ -1,133 +1,32 @@ -import { useNavigate } from 'react-router-dom'; -import type { Toast } from '@vegaprotocol/ui-toolkit'; -import { Dialog, Intent, useToasts } from '@vegaprotocol/ui-toolkit'; +import { Dialog, Intent } from '@vegaprotocol/ui-toolkit'; import { t } from '@vegaprotocol/i18n'; -import { create } from 'zustand'; -import { persist } from 'zustand/middleware'; import { useEnvironment } from '@vegaprotocol/environment'; -import { useLocalStorage } from '@vegaprotocol/react-helpers'; import { WelcomeDialogContent } from './welcome-dialog-content'; -import { Links, Routes } from '../../pages/client-router'; -import { useGlobalStore } from '../../stores'; -import { - useGetOnboardingStep, - OnboardingStep, -} from './use-get-onboarding-step'; -import * as constants from '../constants'; -import { TelemetryApproval } from './telemetry-approval'; -import { useTelemetryApproval } from '../../lib/hooks/use-telemetry-approval'; -import { useCallback } from 'react'; +import { useOnboardingStore } from './use-get-onboarding-step'; -const ONBOARDING_STORAGE_KEY = 'vega_onboarding_dismiss_store'; -export const useOnboardingStore = create<{ - dismissed: boolean; - dismiss: () => void; -}>()( - persist( - (set) => ({ - dismissed: false, - dismiss: () => set(() => ({ dismissed: true })), - }), - { - name: ONBOARDING_STORAGE_KEY, - } - ) -); - -const TELEMETRY_APPROVAL_TOAST_ID = 'telemetry_tost_id'; export const WelcomeDialog = () => { const { VEGA_ENV } = useEnvironment(); - const navigate = useNavigate(); - const [telemetryValue, setTelemetryValue, isTelemetryNeeded, closeTelemetry] = - useTelemetryApproval(); - const [onBoardingViewed] = useLocalStorage(constants.ONBOARDING_VIEWED_KEY); - const dismiss = useOnboardingStore((store) => store.dismiss); const dismissed = useOnboardingStore((store) => store.dismissed); - const currentStep = useGetOnboardingStep(); - const isTelemetryPopupNeeded = - isTelemetryNeeded && - (onBoardingViewed === 'true' || - currentStep > OnboardingStep.ONBOARDING_ORDER_STEP); + const dialogOpen = useOnboardingStore((store) => store.dialogOpen); + const dismiss = useOnboardingStore((store) => store.dismiss); - const isOnboardingDialogNeeded = - onBoardingViewed !== 'true' && - currentStep && - currentStep < OnboardingStep.ONBOARDING_COMPLETE_STEP && - !dismissed; - const marketId = useGlobalStore((store) => store.marketId); - - const onClose = () => { - if (isTelemetryPopupNeeded) { - closeTelemetry(); - } else { - const link = marketId - ? Links[Routes.MARKET](marketId) - : Links[Routes.HOME](); - navigate(link); - dismiss(); - } - }; - - const [setToast, hasToast, removeToast] = useToasts((store) => [ - store.setToast, - store.hasToast, - store.remove, - ]); - const onApprovalClose = useCallback(() => { - closeTelemetry(); - removeToast(TELEMETRY_APPROVAL_TOAST_ID); - }, [removeToast, closeTelemetry]); - - const setTelemetryApprovalAndClose = useCallback( - (value: string) => { - setTelemetryValue(value); - onApprovalClose(); - }, - [setTelemetryValue, onApprovalClose] - ); - - if (isTelemetryPopupNeeded) { - const toast: Toast = { - id: TELEMETRY_APPROVAL_TOAST_ID, - intent: Intent.Primary, - content: ( - <> -

    - {t('Improve vega console')} -

    - - - ), - onClose: onApprovalClose, - }; - if (!hasToast(TELEMETRY_APPROVAL_TOAST_ID)) { - setToast(toast); - } - return; - } - - const title = ( - - {t('Console')}{' '} - - {VEGA_ENV} - - - ); - - return isOnboardingDialogNeeded ? ( + return ( + {t('Console')}{' '} + + {VEGA_ENV} + + + } size="medium" - onChange={onClose} + onChange={() => dismiss()} intent={Intent.None} dataTestId="welcome-dialog" > - ) : null; + ); }; diff --git a/apps/trading/lib/hooks/use-top-traded-markets.tsx b/apps/trading/lib/hooks/use-top-traded-markets.tsx new file mode 100644 index 000000000..38cd3276b --- /dev/null +++ b/apps/trading/lib/hooks/use-top-traded-markets.tsx @@ -0,0 +1,13 @@ +import orderBy from 'lodash/orderBy'; +import { calcTradedFactor, useMarketList } from '@vegaprotocol/markets'; +import { isMarketActive } from '../utils'; + +export const useTopTradedMarkets = () => { + const { data, loading, error } = useMarketList(); + + const activeMarkets = data?.filter((m) => isMarketActive(m.state)); + const marketsByTopTraded = data + ? orderBy(activeMarkets, (m) => calcTradedFactor(m), 'desc') + : undefined; + return { data: marketsByTopTraded, loading, error }; +}; diff --git a/apps/trading/pages/_app.page.tsx b/apps/trading/pages/_app.page.tsx index c3e76a848..188c9f889 100644 --- a/apps/trading/pages/_app.page.tsx +++ b/apps/trading/pages/_app.page.tsx @@ -49,6 +49,7 @@ import { import { ViewingBanner } from '../components/viewing-banner'; import { NavHeader } from '../components/navbar/nav-header'; import { Routes as AppRoutes } from './client-router'; +import { Telemetry } from '../components/telemetry'; const DEFAULT_TITLE = t('Welcome to Vega trading!'); @@ -125,6 +126,7 @@ function AppBody({ Component }: AppProps) { +
    ); } diff --git a/libs/cypress/src/lib/commands/vega-wallet-connect.ts b/libs/cypress/src/lib/commands/vega-wallet-connect.ts index 5ca985bdd..64d430a8f 100644 --- a/libs/cypress/src/lib/commands/vega-wallet-connect.ts +++ b/libs/cypress/src/lib/commands/vega-wallet-connect.ts @@ -61,10 +61,15 @@ export function addVegaWalletConnect() { }); } +const onboardingViewedState = { state: { dismissed: true }, version: 0 }; + export function addSetVegaWallet() { Cypress.Commands.add('setVegaWallet', () => { cy.window().then((win) => { - win.localStorage.setItem('vega_onboarding_viewed', 'true'); + win.localStorage.setItem( + 'vega_onboarding', + JSON.stringify(onboardingViewedState) + ); win.localStorage.setItem('vega_telemetry_approval', 'false'); win.localStorage.setItem('vega_telemetry_viewed', 'true'); win.localStorage.setItem( @@ -82,7 +87,10 @@ export function addSetVegaWallet() { export function addSetOnBoardingViewed() { Cypress.Commands.add('setOnBoardingViewed', () => { cy.window().then((win) => { - win.localStorage.setItem('vega_onboarding_viewed', 'true'); + win.localStorage.setItem( + 'vega_onboarding', + JSON.stringify(onboardingViewedState) + ); win.localStorage.setItem('vega_telemetry_approval', 'false'); win.localStorage.setItem('vega_telemetry_viewed', 'true'); }); diff --git a/libs/ui-toolkit/src/components/icon/vega-icons/svg-icons/icon-eye-off.tsx b/libs/ui-toolkit/src/components/icon/vega-icons/svg-icons/icon-eye-off.tsx index 31aae4fc8..74c558b9d 100644 --- a/libs/ui-toolkit/src/components/icon/vega-icons/svg-icons/icon-eye-off.tsx +++ b/libs/ui-toolkit/src/components/icon/vega-icons/svg-icons/icon-eye-off.tsx @@ -1,7 +1,8 @@ export const IconEyeOff = ({ size = 16 }: { size: number }) => { return ( - + + ); }; diff --git a/libs/ui-toolkit/src/components/trading-button/trading-button.tsx b/libs/ui-toolkit/src/components/trading-button/trading-button.tsx index 48c6ac9b2..8ffe55cdc 100644 --- a/libs/ui-toolkit/src/components/trading-button/trading-button.tsx +++ b/libs/ui-toolkit/src/components/trading-button/trading-button.tsx @@ -6,6 +6,7 @@ import type { ReactNode, } from 'react'; import { Intent } from '../../utils/intent'; +import { Link } from 'react-router-dom'; type TradingButtonProps = { size?: 'large' | 'medium' | 'small' | 'extra-small'; @@ -119,30 +120,22 @@ export const TradingButton = forwardRef< ) ); -export const TradingAnchorButton = forwardRef< - HTMLAnchorElement, - AnchorHTMLAttributes & TradingButtonProps ->( - ( - { - size = 'medium', - intent = Intent.None, - icon, - href, - children, - className, - subLabel, - ...props - }, - ref - ) => ( - - - - ) +export const TradingAnchorButton = ({ + size = 'medium', + intent = Intent.None, + icon, + href, + children, + className, + subLabel, + ...props +}: AnchorHTMLAttributes & + TradingButtonProps & { href: string }) => ( + + + ); From 01ca05a313c620b3f67058e17cb58a67c0347675 Mon Sep 17 00:00:00 2001 From: "m.ray" <16125548+MadalinaRaicu@users.noreply.github.com> Date: Thu, 14 Sep 2023 23:57:15 +0300 Subject: [PATCH 18/31] chore(trading): update governance variables (#4766) Co-authored-by: Matthew Russell --- .../app/components/proposals/proposals-table.tsx | 2 +- .../proposal/signature-bundle/bundle-signers.tsx | 2 +- .../src/app/routes/validators/validators-page.tsx | 2 +- .../trading/client-pages/markets/markets-page.tsx | 4 ++-- .../market-successor-proposal-banner.tsx | 2 +- apps/trading/components/navbar/navbar.tsx | 2 +- .../welcome-dialog/proposed-markets.tsx | 2 +- .../network-switcher/network-switcher.tsx | 2 +- libs/environment/src/hooks/use-links.ts | 15 +++++++++------ .../components/market-info/market-info-panels.tsx | 2 +- .../components/asset-proposal-notification.tsx | 2 +- .../components/market-proposal-notification.tsx | 2 +- .../src/components/proposal-actions-dropdown.tsx | 2 +- .../use-update-network-paramaters-toasts.tsx | 2 +- 14 files changed, 23 insertions(+), 20 deletions(-) diff --git a/apps/explorer/src/app/components/proposals/proposals-table.tsx b/apps/explorer/src/app/components/proposals/proposals-table.tsx index cd794c3a9..2986def3d 100644 --- a/apps/explorer/src/app/components/proposals/proposals-table.tsx +++ b/apps/explorer/src/app/components/proposals/proposals-table.tsx @@ -33,7 +33,7 @@ export const ProposalsTable = ({ data }: ProposalsTableProps) => { const { params } = useNetworkParams([ NetworkParams.governance_proposal_market_requiredMajority, ]); - const tokenLink = useLinks(DApp.Token); + const tokenLink = useLinks(DApp.Governance); const requiredMajorityPercentage = useMemo(() => { const requiredMajority = params?.governance_proposal_market_requiredMajority ?? 1; diff --git a/apps/explorer/src/app/components/txs/details/proposal/signature-bundle/bundle-signers.tsx b/apps/explorer/src/app/components/txs/details/proposal/signature-bundle/bundle-signers.tsx index 154a717e8..07fb67724 100644 --- a/apps/explorer/src/app/components/txs/details/proposal/signature-bundle/bundle-signers.tsx +++ b/apps/explorer/src/app/components/txs/details/proposal/signature-bundle/bundle-signers.tsx @@ -35,7 +35,7 @@ export const BundleSigners = ({ tx, id, }: BundleSignersProps) => { - const tokenLink = useLinks(DApp.Token); + const tokenLink = useLinks(DApp.Governance); const bridgeFunction: BridgeFunction = tx?.changes?.erc20 && 'contractAddress' in tx.changes.erc20 diff --git a/apps/explorer/src/app/routes/validators/validators-page.tsx b/apps/explorer/src/app/routes/validators/validators-page.tsx index 3c2d888bc..02a7e4877 100644 --- a/apps/explorer/src/app/routes/validators/validators-page.tsx +++ b/apps/explorer/src/app/routes/validators/validators-page.tsx @@ -139,7 +139,7 @@ export const ValidatorsPage = () => { const [vegaDialog, setVegaDialog] = useState(false); const [tmDialog, setTmDialog] = useState(false); - const tokenLink = useLinks(DApp.Token); + const tokenLink = useLinks(DApp.Governance); return ( <> diff --git a/apps/trading/client-pages/markets/markets-page.tsx b/apps/trading/client-pages/markets/markets-page.tsx index b32bd0a0f..666e63d81 100644 --- a/apps/trading/client-pages/markets/markets-page.tsx +++ b/apps/trading/client-pages/markets/markets-page.tsx @@ -21,8 +21,8 @@ export const MarketsPage = () => { updateTitle: store.updateTitle, })); - const tokenLink = useLinks(DApp.Token); - const externalLink = tokenLink(TOKEN_NEW_MARKET_PROPOSAL); + const governanceLink = useLinks(DApp.Governance); + const externalLink = governanceLink(TOKEN_NEW_MARKET_PROPOSAL); useEffect(() => { updateTitle(titlefy(['Markets'])); diff --git a/apps/trading/components/market-banner/market-successor-proposal-banner.tsx b/apps/trading/components/market-banner/market-successor-proposal-banner.tsx index 8797909bf..bccac258d 100644 --- a/apps/trading/components/market-banner/market-successor-proposal-banner.tsx +++ b/apps/trading/components/market-banner/market-successor-proposal-banner.tsx @@ -29,7 +29,7 @@ export const MarketSuccessorProposalBanner = ({ ?.successorConfiguration?.parentMarketId === marketId ) ?? []; const [visible, setVisible] = useState(true); - const tokenLink = useLinks(DApp.Token); + const tokenLink = useLinks(DApp.Governance); if (visible && successors.length) { return ( void }) => { - + {t('Governance')} diff --git a/apps/trading/components/welcome-dialog/proposed-markets.tsx b/apps/trading/components/welcome-dialog/proposed-markets.tsx index ecc453621..b7d658c74 100644 --- a/apps/trading/components/welcome-dialog/proposed-markets.tsx +++ b/apps/trading/components/welcome-dialog/proposed-markets.tsx @@ -41,7 +41,7 @@ export const ProposedMarkets = () => { proposal.terms.change.instrument.code, })); - const tokenLink = useLinks(DApp.Token); + const tokenLink = useLinks(DApp.Governance); return useMemo( () => (
    diff --git a/libs/environment/src/components/network-switcher/network-switcher.tsx b/libs/environment/src/components/network-switcher/network-switcher.tsx index 991b185f2..2bcd96028 100644 --- a/libs/environment/src/components/network-switcher/network-switcher.tsx +++ b/libs/environment/src/components/network-switcher/network-switcher.tsx @@ -87,7 +87,7 @@ export const NetworkSwitcher = ({ className, }: NetworkSwitcherProps) => { const { VEGA_ENV, VEGA_NETWORKS } = useEnvironment(); - const tokenLink = useLinks(DApp.Token); + const tokenLink = useLinks(DApp.Governance); const [isOpen, setOpen] = useState(false); const [isAdvancedView, setAdvancedView] = useState(false); diff --git a/libs/environment/src/hooks/use-links.ts b/libs/environment/src/hooks/use-links.ts index 785449568..0c76a3056 100644 --- a/libs/environment/src/hooks/use-links.ts +++ b/libs/environment/src/hooks/use-links.ts @@ -11,7 +11,7 @@ type Net = Exclude; export enum DApp { Explorer = 'Explorer', Console = 'Console', - Token = 'Token', + Governance = 'Governance', } type DAppLinks = { @@ -45,7 +45,7 @@ const ConsoleLinks = { [Networks.MAINNET_MIRROR]: 'https://console.mainnet-mirror.vega.rocks', }; -const TokenLinks = { +const GovernanceLinks = { ...EmptyLinks, [Networks.DEVNET]: 'https://dev.governance.vega.xyz', [Networks.STAGNET1]: 'https://governance.stagnet1.vega.rocks', @@ -59,7 +59,7 @@ const TokenLinks = { const Links: { [k in DApp]: DAppLinks } = { [DApp.Explorer]: ExplorerLinks, [DApp.Console]: ConsoleLinks, - [DApp.Token]: TokenLinks, + [DApp.Governance]: GovernanceLinks, }; export const DocsLinks = VEGA_DOCS_URL @@ -88,7 +88,7 @@ export const useLinks = (dapp: DApp, network?: Net) => { useEnvironment(); const fallback = { [DApp.Explorer]: VEGA_EXPLORER_URL, - [DApp.Token]: VEGA_TOKEN_URL, + [DApp.Governance]: VEGA_TOKEN_URL, [DApp.Console]: VEGA_CONSOLE_URL, }; @@ -99,7 +99,10 @@ export const useLinks = (dapp: DApp, network?: Net) => { let baseUrl = trim(Links[dapp][net], '/'); if (baseUrl.length === 0 && Object.keys(fallback).includes(dapp)) { - baseUrl = trim(fallback[dapp as DApp.Explorer | DApp.Token] || '', '/'); + baseUrl = trim( + fallback[dapp as DApp.Explorer | DApp.Governance] || '', + '/' + ); } const link = useCallback( @@ -134,7 +137,7 @@ export const TOKEN_VALIDATOR = '/validators/:id'; * Generates link to the protocol upgrade proposal details on Governance */ export const useProtocolUpgradeProposalLink = () => { - const governance = useLinks(DApp.Token); + const governance = useLinks(DApp.Governance); return (releaseTag: string, blockHeight: string) => governance( TOKEN_PROTOCOL_UPGRADE_PROPOSAL.replace( 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 a1acca924..3f2b9a304 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 @@ -277,7 +277,7 @@ const SuccessionLineItem = ({ }); const marketData = data?.market; - const governanceLink = useLinks(DApp.Token); + const governanceLink = useLinks(DApp.Governance); const proposalLink = marketData?.proposal?.id ? governanceLink(TOKEN_PROPOSAL.replace(':id', marketData?.proposal?.id)) : undefined; diff --git a/libs/proposals/src/components/asset-proposal-notification.tsx b/libs/proposals/src/components/asset-proposal-notification.tsx index 2301d8a3e..9c2a71937 100644 --- a/libs/proposals/src/components/asset-proposal-notification.tsx +++ b/libs/proposals/src/components/asset-proposal-notification.tsx @@ -10,7 +10,7 @@ type AssetProposalNotificationProps = { export const AssetProposalNotification = ({ assetId, }: AssetProposalNotificationProps) => { - const tokenLink = useLinks(DApp.Token); + const tokenLink = useLinks(DApp.Governance); const { data: proposal } = useUpdateProposal({ id: assetId, proposalType: Schema.ProposalType.TYPE_UPDATE_ASSET, diff --git a/libs/proposals/src/components/market-proposal-notification.tsx b/libs/proposals/src/components/market-proposal-notification.tsx index 99ee236fc..07f82804d 100644 --- a/libs/proposals/src/components/market-proposal-notification.tsx +++ b/libs/proposals/src/components/market-proposal-notification.tsx @@ -10,7 +10,7 @@ type MarketProposalNotificationProps = { export const MarketProposalNotification = ({ marketId, }: MarketProposalNotificationProps) => { - const tokenLink = useLinks(DApp.Token); + const tokenLink = useLinks(DApp.Governance); const { data: proposal } = useUpdateProposal({ id: marketId, proposalType: Schema.ProposalType.TYPE_UPDATE_MARKET, diff --git a/libs/proposals/src/components/proposal-actions-dropdown.tsx b/libs/proposals/src/components/proposal-actions-dropdown.tsx index 369ec044c..49cbe2344 100644 --- a/libs/proposals/src/components/proposal-actions-dropdown.tsx +++ b/libs/proposals/src/components/proposal-actions-dropdown.tsx @@ -9,7 +9,7 @@ import { t } from '@vegaprotocol/i18n'; import { DApp, TOKEN_PROPOSAL, useLinks } from '@vegaprotocol/environment'; export const ProposalActionsDropdown = ({ id }: { id: string }) => { - const linkCreator = useLinks(DApp.Token); + const linkCreator = useLinks(DApp.Governance); return ( diff --git a/libs/proposals/src/lib/proposals-hooks/use-update-network-paramaters-toasts.tsx b/libs/proposals/src/lib/proposals-hooks/use-update-network-paramaters-toasts.tsx index 8b620c40b..35970bb41 100644 --- a/libs/proposals/src/lib/proposals-hooks/use-update-network-paramaters-toasts.tsx +++ b/libs/proposals/src/lib/proposals-hooks/use-update-network-paramaters-toasts.tsx @@ -26,7 +26,7 @@ const UpdateNetworkParameterToastContent = ({ }: { proposal: Proposal; }) => { - const tokenLink = useLinks(DApp.Token); + const tokenLink = useLinks(DApp.Governance); const change = proposal.terms.change as UpdateNetworkParameter; const title = t('Network change proposal %s').replace( '%s', From b29c268257d3ad459726ce0248d9b332e47140c3 Mon Sep 17 00:00:00 2001 From: "m.ray" <16125548+MadalinaRaicu@users.noreply.github.com> Date: Thu, 14 Sep 2023 23:57:28 +0300 Subject: [PATCH 19/31] chore(trading): add oracle proofs url to all envs (#4793) --- apps/explorer-e2e/.env.devnet | 2 ++ apps/explorer-e2e/.env.mainnet | 1 + apps/explorer-e2e/.env.testnet | 1 + apps/explorer/.env.capsule | 1 + apps/explorer/.env.devnet | 1 + apps/explorer/.env.mainnet | 1 + apps/explorer/.env.mainnet-mirror | 1 + apps/explorer/.env.stagnet1 | 1 + apps/explorer/.env.testnet | 1 + apps/explorer/.env.validators-testnet | 1 + apps/explorer/.env.vegacapsule | 3 ++- apps/governance-e2e/.env | 2 ++ apps/governance-e2e/.env.devnet | 1 + apps/governance-e2e/.env.mainnet | 1 + apps/governance-e2e/.env.testnet | 1 + apps/governance/.env.capsule | 2 ++ apps/governance/.env.devnet | 2 ++ apps/governance/.env.mainnet | 1 + apps/governance/.env.mainnet-mirror | 1 + apps/governance/.env.stagnet1 | 1 + apps/governance/.env.testnet | 1 + apps/governance/.env.validators-testnet | 1 + apps/trading-e2e/.env | 2 ++ apps/trading-e2e/.env.capsule | 2 ++ apps/trading/.env.mainnet | 3 +++ apps/trading/.env.stagnet1 | 2 ++ apps/trading/.env.testnet | 1 + apps/trading/.env.validators-testnet | 1 + 28 files changed, 38 insertions(+), 1 deletion(-) diff --git a/apps/explorer-e2e/.env.devnet b/apps/explorer-e2e/.env.devnet index de6c1a705..2533ef0cc 100644 --- a/apps/explorer-e2e/.env.devnet +++ b/apps/explorer-e2e/.env.devnet @@ -4,6 +4,8 @@ NX_TENDERMINT_WEBSOCKET_URL=wss://n04.d.vega.xyz/tm/websocket NX_VEGA_URL=https://api.n04.d.vega.xyz/graphql NX_VEGA_ENV=DEVNET NX_BLOCK_EXPLORER=https://be.devnet1.vega.xyz/rest +NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json + # App flags NX_EXPLORER_ASSETS=1 diff --git a/apps/explorer-e2e/.env.mainnet b/apps/explorer-e2e/.env.mainnet index 8336b670f..66e33d4e1 100644 --- a/apps/explorer-e2e/.env.mainnet +++ b/apps/explorer-e2e/.env.mainnet @@ -4,6 +4,7 @@ NX_TENDERMINT_WEBSOCKET_URL=wss://mainnet-observer-proxy01.ops.vega.xyz/websocke NX_VEGA_URL=https://api.vega.community/graphql NX_VEGA_ENV=MAINNET NX_BLOCK_EXPLORER=https://be.explorer.vega.xyz/rest +NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json # App flags NX_EXPLORER_ASSETS=1 diff --git a/apps/explorer-e2e/.env.testnet b/apps/explorer-e2e/.env.testnet index bf4f7174e..f184fac2b 100644 --- a/apps/explorer-e2e/.env.testnet +++ b/apps/explorer-e2e/.env.testnet @@ -4,6 +4,7 @@ NX_TENDERMINT_WEBSOCKET_URL=wss://lb.testnet.vega.xyz/tm/websocket NX_VEGA_URL=https://api.n07.testnet.vega.xyz/graphql NX_VEGA_ENV=TESTNET NX_BLOCK_EXPLORER=https://be.testnet.vega.xyz/rest +NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json # App flags NX_EXPLORER_ASSETS=1 diff --git a/apps/explorer/.env.capsule b/apps/explorer/.env.capsule index 83e128a14..39ab79e82 100644 --- a/apps/explorer/.env.capsule +++ b/apps/explorer/.env.capsule @@ -3,6 +3,7 @@ NX_VEGA_ENV=CUSTOM NX_ETHERSCAN_URL=https://sepolia.etherscan.io NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/test/announcements.json NX_VEGA_EXPLORER_URL=/ +NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json # App flags NX_EXPLORER_TXS_LIST=0 diff --git a/apps/explorer/.env.devnet b/apps/explorer/.env.devnet index 7c429a0a6..abe211865 100644 --- a/apps/explorer/.env.devnet +++ b/apps/explorer/.env.devnet @@ -8,6 +8,7 @@ NX_VEGA_URL=https://api.devnet1.vega.xyz/graphql NX_VEGA_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/devnet1/vegawallet-devnet1.toml NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json NX_VEGA_EXPLORER_URL=/ +NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json NX_TENDERMINT_URL=https://tm.be.devnet1.vega.xyz/ NX_TENDERMINT_WEBSOCKET_URL=wss://be.devnet1.vega.xyz/websocket diff --git a/apps/explorer/.env.mainnet b/apps/explorer/.env.mainnet index 69a4d78f9..21423c3db 100644 --- a/apps/explorer/.env.mainnet +++ b/apps/explorer/.env.mainnet @@ -9,6 +9,7 @@ NX_VEGA_GOVERNANCE_URL=https://governance.vega.xyz NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/mainnet/announcements.json NX_VEGA_EXPLORER_URL=https://explorer.vega.xyz/ NX_VEGA_CONSOLE_URL=https://console.vega.xyz +NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json NX_TENDERMINT_URL=https://be.vega.community NX_TENDERMINT_WEBSOCKET_URL=wss://be.vega.community/websocket diff --git a/apps/explorer/.env.mainnet-mirror b/apps/explorer/.env.mainnet-mirror index c97564f1e..527870b91 100644 --- a/apps/explorer/.env.mainnet-mirror +++ b/apps/explorer/.env.mainnet-mirror @@ -9,6 +9,7 @@ NX_VEGA_GOVERNANCE_URL=https://governance.mainnet-mirror.vega.rocks NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/mainnet/announcements.json NX_VEGA_EXPLORER_URL=https://explorer.mainnet-mirror.vega.rocks/ NX_VEGA_CONSOLE_URL=https://console.mainnet-mirror.vega.rocks +NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json NX_TENDERMINT_URL=https://be.mainnet-mirror.vega.rocks NX_TENDERMINT_WEBSOCKET_URL=wss://be.mainnet-mirror.vega.rocks/websocket diff --git a/apps/explorer/.env.stagnet1 b/apps/explorer/.env.stagnet1 index fa167a129..73fd98dce 100644 --- a/apps/explorer/.env.stagnet1 +++ b/apps/explorer/.env.stagnet1 @@ -1,2 +1,3 @@ # .env is stagnet1, so there are no overrides required NX_VEGA_NETWORKS='{"TESTNET":"https://explorer.fairground.wtf","MAINNET":"https://explorer.vega.xyz","STAGNET1":"https://stagnet1.explorer.vega.xyz"}' +NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json diff --git a/apps/explorer/.env.testnet b/apps/explorer/.env.testnet index 56d569ce6..eaa7350d5 100644 --- a/apps/explorer/.env.testnet +++ b/apps/explorer/.env.testnet @@ -9,6 +9,7 @@ NX_VEGA_GOVERNANCE_URL=https://governance.fairground.wtf NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json NX_VEGA_EXPLORER_URL=https://explorer.fairground.wtf NX_VEGA_CONSOLE_URL=https://console.fairground.wtf +NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json NX_TENDERMINT_URL=https://tm.be.testnet.vega.xyz NX_TENDERMINT_WEBSOCKET_URL=wss://be.testnet.vega.xyz/websocket diff --git a/apps/explorer/.env.validators-testnet b/apps/explorer/.env.validators-testnet index 3c609c7c2..348f6ce45 100644 --- a/apps/explorer/.env.validators-testnet +++ b/apps/explorer/.env.validators-testnet @@ -11,6 +11,7 @@ NX_BLOCK_EXPLORER=https://be.validators-testnet.vega.rocks/rest NX_VEGA_GOVERNANCE_URL=https://governance.validators-testnet.vega.rocks NX_VEGA_EXPLORER_URL=https://explorer.validators-testnet.vega.rocks/ NX_VEGA_CONSOLE_URL=https://trading.validators-testnet.vega.rocks/ +NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json NX_TENDERMINT_URL=https://tm.be.validators-testnet.vega.rocks NX_TENDERMINT_WEBSOCKET_URL=wss://be.validators-testnet.vega.xyz/websocket diff --git a/apps/explorer/.env.vegacapsule b/apps/explorer/.env.vegacapsule index cf7308afe..ad5d2d29e 100644 --- a/apps/explorer/.env.vegacapsule +++ b/apps/explorer/.env.vegacapsule @@ -5,4 +5,5 @@ NX_VEGA_ENV=CUSTOM NX_BLOCK_EXPLORER= NX_ETHERSCAN_URL=https://sepolia.etherscan.io NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/test/announcements.json -NX_VEGA_EXPLORER_URL=/ \ No newline at end of file +NX_VEGA_EXPLORER_URL=/ +NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json diff --git a/apps/governance-e2e/.env b/apps/governance-e2e/.env index 2e6ff789a..aa289efe5 100644 --- a/apps/governance-e2e/.env +++ b/apps/governance-e2e/.env @@ -14,6 +14,8 @@ NX_ETH_LOCAL_PROVIDER_URL=http://localhost:8545/ NX_VEGA_WALLET_URL=http://localhost:1789 NX_VEGA_DOCS_URL=https://docs.vega.xyz/mainnet NX_TRANCHES_SERVICE_URL=https://tranches-stagnet1-k8s.ops.vega.xyz +NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json + NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/test/announcements.json NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions NX_WALLETCONNECT_PROJECT_ID=fe8091dc35738863e509fc4947525c72 diff --git a/apps/governance-e2e/.env.devnet b/apps/governance-e2e/.env.devnet index 53db0acbd..7a3080201 100644 --- a/apps/governance-e2e/.env.devnet +++ b/apps/governance-e2e/.env.devnet @@ -3,3 +3,4 @@ NX_VEGA_ENV=DEVNET NX_VEGA_URL=https://api.n04.d.vega.xyz/graphql NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8 NX_ETHERSCAN_URL=https://sepolia.etherscan.io +NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json diff --git a/apps/governance-e2e/.env.mainnet b/apps/governance-e2e/.env.mainnet index 7596bcd07..9a252e56e 100644 --- a/apps/governance-e2e/.env.mainnet +++ b/apps/governance-e2e/.env.mainnet @@ -3,3 +3,4 @@ NX_VEGA_ENV=MAINNET NX_VEGA_URL=https://api.vega.community/graphql NX_ETHEREUM_PROVIDER_URL=https://mainnet.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8 NX_ETHERSCAN_URL=https://etherscan.io +NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json diff --git a/apps/governance-e2e/.env.testnet b/apps/governance-e2e/.env.testnet index 218bc4e94..76a430550 100644 --- a/apps/governance-e2e/.env.testnet +++ b/apps/governance-e2e/.env.testnet @@ -3,3 +3,4 @@ NX_VEGA_ENV=TESTNET NX_VEGA_URL=https://api.n07.testnet.vega.xyz/graphql NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8 NX_ETHERSCAN_URL=https://sepolia.etherscan.io +NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json diff --git a/apps/governance/.env.capsule b/apps/governance/.env.capsule index 9e818f3ac..64d641033 100644 --- a/apps/governance/.env.capsule +++ b/apps/governance/.env.capsule @@ -22,6 +22,8 @@ NX_VEGA_REST_URL=http://localhost:3008/api/v2/ NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/firefox/addon/vega-wallet-fairground +NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json + NX_TENDERMINT_URL=http://localhost:26617 NX_TENDERMINT_WEBSOCKET_URL=wss://localhost:26617/websocket diff --git a/apps/governance/.env.devnet b/apps/governance/.env.devnet index e1a177258..3acb4de4d 100644 --- a/apps/governance/.env.devnet +++ b/apps/governance/.env.devnet @@ -19,6 +19,8 @@ NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/firefox/addon/vega-wallet-fa NX_TENDERMINT_URL=https://tm.be.devnet1.vega.xyz/ NX_TENDERMINT_WEBSOCKET_URL=wss://be.devnet1.vega.xyz/websocket +NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json + # Cosmic elevator flags NX_SUCCESSOR_MARKETS=true diff --git a/apps/governance/.env.mainnet b/apps/governance/.env.mainnet index cf9e143f5..9208e58b4 100644 --- a/apps/governance/.env.mainnet +++ b/apps/governance/.env.mainnet @@ -16,6 +16,7 @@ NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/annou NX_VEGA_REST_URL=https://api.vega.community/api/v2/ NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/firefox/addon/vega-wallet-mainnet +NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json NX_TENDERMINT_URL=https://be.vega.community NX_TENDERMINT_WEBSOCKET_URL=wss://be.vega.community/websocket diff --git a/apps/governance/.env.mainnet-mirror b/apps/governance/.env.mainnet-mirror index 466f87123..3e20d16a3 100644 --- a/apps/governance/.env.mainnet-mirror +++ b/apps/governance/.env.mainnet-mirror @@ -15,6 +15,7 @@ NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/annou NX_VEGA_REST_URL=https://api.mainnet-mirror.vega.rocks/api/v2/ NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/firefox/addon/vega-wallet-mainnet +NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json NX_TENDERMINT_URL=https://be.mainnet-mirror.vega.rocks NX_TENDERMINT_WEBSOCKET_URL=wss://be.mainnet-mirror.vega.rocks/websocket diff --git a/apps/governance/.env.stagnet1 b/apps/governance/.env.stagnet1 index 64171ba1f..29d15032f 100644 --- a/apps/governance/.env.stagnet1 +++ b/apps/governance/.env.stagnet1 @@ -9,6 +9,7 @@ NX_DELEGATIONS_PAGINATION=50 NX_TRANCHES_SERVICE_URL=https://tranches-stagnet1-k8s.ops.vega.xyz NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json NX_VEGA_REST_URL=https://api.n00.stagnet1.vega.xyz/api/v2/ +NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/firefox/addon/vega-wallet-fairground diff --git a/apps/governance/.env.testnet b/apps/governance/.env.testnet index 408804c11..38cf946ce 100644 --- a/apps/governance/.env.testnet +++ b/apps/governance/.env.testnet @@ -14,6 +14,7 @@ NX_TRANCHES_SERVICE_URL=https://tranches-testnet-k8s.ops.vega.xyz NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json NX_VEGA_REST_URL=https://api.n07.testnet.vega.xyz/api/v2/ NX_SENTRY_DSN=https://4b8c8a8ba07742648aa4dfe1b8d17e40@o286262.ingest.sentry.io/5882996 +NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/firefox/addon/vega-wallet-fairground diff --git a/apps/governance/.env.validators-testnet b/apps/governance/.env.validators-testnet index d4489c8bc..7be31358f 100644 --- a/apps/governance/.env.validators-testnet +++ b/apps/governance/.env.validators-testnet @@ -11,6 +11,7 @@ NX_VEGA_EXPLORER_URL=https://explorer.validators-testnet.vega.rocks/ NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/announcements/fairground/announcements.json NX_VEGA_REST_URL=https://api-validators-testnet.vega.rocks/api/v2/ NX_SENTRY_DSN=https://4b8c8a8ba07742648aa4dfe1b8d17e40@o286262.ingest.sentry.io/5882996 +NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/firefox/addon/vega-wallet-fairground diff --git a/apps/trading-e2e/.env b/apps/trading-e2e/.env index a575afdea..95b8d5c19 100644 --- a/apps/trading-e2e/.env +++ b/apps/trading-e2e/.env @@ -15,6 +15,8 @@ NX_ETH_LOCAL_PROVIDER_URL=http://localhost:8545/ NX_ETH_WALLET_MNEMONIC="ozone access unlock valid olympic save include omit supply green clown session" NX_WALLETCONNECT_PROJECT_ID=fe8091dc35738863e509fc4947525c72 NX_SENTRY_DSN=https://dummy@o999999.ingest.sentry.io/9999999 +NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json + # Expose some env vars to cypress environment for market setup CYPRESS_ETH_WALLET_MNEMONIC=ozone access unlock valid olympic save include omit supply green clown session diff --git a/apps/trading-e2e/.env.capsule b/apps/trading-e2e/.env.capsule index 145a6fb7c..cf2ef8201 100644 --- a/apps/trading-e2e/.env.capsule +++ b/apps/trading-e2e/.env.capsule @@ -12,6 +12,8 @@ NX_VEGA_URL=http://localhost:3008/graphql NX_VEGA_WALLET_URL=http://localhost:1789 NX_ETH_LOCAL_PROVIDER_URL=http://localhost:8545/ NX_ETH_WALLET_MNEMONIC="ozone access unlock valid olympic save include omit supply green clown session" +NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json + # Expose some env vars to cypress environment for market setup CYPRESS_ETH_WALLET_MNEMONIC=ozone access unlock valid olympic save include omit supply green clown session diff --git a/apps/trading/.env.mainnet b/apps/trading/.env.mainnet index d81fa2908..547137f08 100644 --- a/apps/trading/.env.mainnet +++ b/apps/trading/.env.mainnet @@ -15,6 +15,9 @@ NX_VEGA_INCIDENT_URL=https://blog.vega.xyz/tagged/vega-incident-reports NX_VEGA_CONSOLE_URL=https://console.vega.xyz NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-mainnet/codfcglpplgmmlokgilfkpcjnmkbfiel NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/firefox/addon/vega-wallet-mainnet +NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json + + # TAG name of the current app version - TODO: bump to the latest upon release NX_APP_VERSION=v0.21.1-core-0.72.14 diff --git a/apps/trading/.env.stagnet1 b/apps/trading/.env.stagnet1 index f2e4129c8..fc93d40cb 100644 --- a/apps/trading/.env.stagnet1 +++ b/apps/trading/.env.stagnet1 @@ -15,6 +15,8 @@ NX_ANNOUNCEMENTS_CONFIG_URL=https://raw.githubusercontent.com/vegaprotocol/annou NX_VEGA_INCIDENT_URL=https://blog.vega.xyz/tagged/vega-incident-reports NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/firefox/addon/vega-wallet-fairground +NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json + # Cosmic elevator flags NX_SUCCESSOR_MARKETS=true diff --git a/apps/trading/.env.testnet b/apps/trading/.env.testnet index fb03c98f4..78caf98d6 100644 --- a/apps/trading/.env.testnet +++ b/apps/trading/.env.testnet @@ -16,6 +16,7 @@ NX_VEGA_INCIDENT_URL=https://blog.vega.xyz/tagged/vega-incident-reports NX_VEGA_CONSOLE_URL=https://console.fairground.wtf NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/firefox/addon/vega-wallet-fairground +NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json # Cosmic elevator flags NX_SUCCESSOR_MARKETS=true diff --git a/apps/trading/.env.validators-testnet b/apps/trading/.env.validators-testnet index 21af40de4..f36a8c454 100644 --- a/apps/trading/.env.validators-testnet +++ b/apps/trading/.env.validators-testnet @@ -17,6 +17,7 @@ NX_VEGA_CONSOLE_URL=https://trading.validators-testnet.vega.rocks NX_CHROME_EXTENSION_URL=https://chrome.google.com/webstore/detail/vega-wallet-fairground/nmmjkiafpmphlikhefgjbblebfgclikn NX_MOZILLA_EXTENSION_URL=https://addons.mozilla.org/firefox/addon/vega-wallet-fairground +NX_ORACLE_PROOFS_URL=https://raw.githubusercontent.com/vegaprotocol/well-known/main/__generated__/oracle-proofs.json # Cosmic elevator flags NX_SUCCESSOR_MARKETS=true From d7e2da7a548e85db86aa192313d7d0066bd79767 Mon Sep 17 00:00:00 2001 From: Matthew Russell Date: Thu, 14 Sep 2023 14:00:59 -0700 Subject: [PATCH 20/31] fix(trading): missing styles for tooltip in positions table (#4780) --- libs/positions/src/lib/positions-table.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libs/positions/src/lib/positions-table.tsx b/libs/positions/src/lib/positions-table.tsx index 27804419c..097149226 100644 --- a/libs/positions/src/lib/positions-table.tsx +++ b/libs/positions/src/lib/positions-table.tsx @@ -368,7 +368,7 @@ export const PositionsTable = ({ DocsLinks?.LOSS_SOCIALIZATION ?? ''; if (!args.data) { - return <>-; + return null; } const losses = parseInt( @@ -377,7 +377,9 @@ export const PositionsTable = ({ if (losses <= 0) { // eslint-disable-next-line react/jsx-no-useless-fragment - return <>{args.valueFormatted}; + return ( + + ); } const lossesFormatted = addDecimalsFormatNumber( From 9ea8c839dbefc533855c8415c6983fd1b0754576 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20M=C5=82odzikowski?= Date: Fri, 15 Sep 2023 08:48:25 +0200 Subject: [PATCH 21/31] feat(ci): use ipfs daemon in dockerfiles (#4786) --- README.md | 16 +++++++++++++++- docker/entrypoint.sh | 11 +++++++++++ docker/node-inside-docker.Dockerfile | 2 ++ docker/node-outside-docker.Dockerfile | 2 ++ 4 files changed, 30 insertions(+), 1 deletion(-) create mode 100755 docker/entrypoint.sh diff --git a/README.md b/README.md index dba942bf3..3ad469c9a 100644 --- a/README.md +++ b/README.md @@ -113,6 +113,20 @@ In order to run a container on port 3000: docker run -p 3000:80 [TAG] ``` +On top of that there are two possible scenarios for running docker image - using nginx server (default) of ipfs daemon. + +to run ipfs on port 3000: + +```bash +docker run -p 3000:80 [TAG] ipfs +``` + +to run nginx on port 3000: + +```bash +docker run -p 3000:80 [TAG] +``` + ## Build instructions The [`docker`](./docker) subfolder has some docker configurations for easily setting up your own hosted version of Console either for the web, or ready for pinning on IPFS. @@ -150,7 +164,7 @@ As a prerequisite you need to perform build of `dist` directory and move its con You can build any of the containers locally with the following command: ```bash -docker build --dockerfile docker/node-outside-docker.Dockerfile . --tag=[TAG] +docker build -f docker/node-outside-docker.Dockerfile . --tag=[TAG] ``` ### Verifying ipfs-hash of existing current application version diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh new file mode 100755 index 000000000..0bc9d09e0 --- /dev/null +++ b/docker/entrypoint.sh @@ -0,0 +1,11 @@ +#!/bin/sh + +daemon="${1:-nginx}" + +if [[ "$daemon" = "nginx" ]]; then + nginx -g 'daemon off;' +elif [[ "$daemon" = "ipfs" ]]; then + ipfs config profile apply server + ipfs config --json Addresses.Gateway '"/ip4/127.0.0.1/tcp/80"' + ipfs daemon +fi diff --git a/docker/node-inside-docker.Dockerfile b/docker/node-inside-docker.Dockerfile index d3baa154c..93b5fa4b2 100644 --- a/docker/node-inside-docker.Dockerfile +++ b/docker/node-inside-docker.Dockerfile @@ -20,6 +20,8 @@ RUN sh docker/docker-build.sh FROM --platform=amd64 nginx:1.23-alpine@sha256:6318314189b40e73145a48060bff4783a116c34cc7241532d0d94198fb2c9629 # configuration of system EXPOSE 80 +COPY docker/entrypoint.sh /entrypoint.sh +ENTRYPOINT [ "/entrypoint.sh" ] # Copy dist COPY docker/nginx.conf /etc/nginx/conf.d/default.conf RUN rm -rf /usr/share/nginx/html/* diff --git a/docker/node-outside-docker.Dockerfile b/docker/node-outside-docker.Dockerfile index e185fa8bc..d5aacba93 100644 --- a/docker/node-outside-docker.Dockerfile +++ b/docker/node-outside-docker.Dockerfile @@ -1,5 +1,7 @@ FROM --platform=amd64 nginx:1.23-alpine@sha256:6318314189b40e73145a48060bff4783a116c34cc7241532d0d94198fb2c9629 EXPOSE 80 +COPY docker/entrypoint.sh /entrypoint.sh +ENTRYPOINT [ "/entrypoint.sh" ] COPY docker/nginx.conf /etc/nginx/conf.d/default.conf RUN rm -rf /usr/share/nginx/html/* COPY ./dist-result/ /usr/share/nginx/html/ From 2fc688f4774be11c7ded225aaddd0436ee3bc626 Mon Sep 17 00:00:00 2001 From: Ben Date: Fri, 15 Sep 2023 12:45:15 +0100 Subject: [PATCH 22/31] chore(trading): fix wallet test (#4802) --- apps/trading-e2e/src/integration/wallet-vega.cy.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/trading-e2e/src/integration/wallet-vega.cy.ts b/apps/trading-e2e/src/integration/wallet-vega.cy.ts index 850b1146d..f0b5c19eb 100644 --- a/apps/trading-e2e/src/integration/wallet-vega.cy.ts +++ b/apps/trading-e2e/src/integration/wallet-vega.cy.ts @@ -10,10 +10,10 @@ const dialogContent = 'dialog-content'; describe('connect vega wallet', { tags: '@smoke', testIsolation: true }, () => { beforeEach(() => { // Using portfolio page as it requires vega wallet connection - cy.visit('/#/portfolio'); cy.mockTradingPage(); cy.mockSubscription(); cy.setOnBoardingViewed(); + cy.visit('/#/portfolio'); cy.get('[data-testid="pathname-/portfolio"]').should('exist'); }); From 5c57106c043e910801685a42fc0f4aef3f50ba17 Mon Sep 17 00:00:00 2001 From: Ben Date: Fri, 15 Sep 2023 12:45:52 +0100 Subject: [PATCH 23/31] chore(trading): delete market info tests (#4804) --- .../src/integration/market-info.cy.ts | 256 ------------------ 1 file changed, 256 deletions(-) delete mode 100644 apps/trading-e2e/src/integration/market-info.cy.ts diff --git a/apps/trading-e2e/src/integration/market-info.cy.ts b/apps/trading-e2e/src/integration/market-info.cy.ts deleted file mode 100644 index 35720c4a6..000000000 --- a/apps/trading-e2e/src/integration/market-info.cy.ts +++ /dev/null @@ -1,256 +0,0 @@ -import { MarketTradingModeMapping } from '@vegaprotocol/types'; -import { MarketState } from '@vegaprotocol/types'; -import compact from 'lodash/compact'; - -const accordionContent = 'accordion-content'; -const blockExplorerLink = 'block-explorer-link'; -const dialogClose = 'dialog-close'; -const dialogContent = 'dialog-content'; -const externalLink = 'external-link'; -const githubLink = 'github-link'; -const liquidityLink = 'view-liquidity-link'; -const marketInfoBtn = 'Info'; -const marketTitle = 'accordion-title'; -const providerName = 'provider-name'; -const row = 'key-value-table-row'; -const verifiedProofs = 'verified-proofs'; - -describe('market info is displayed', { tags: '@smoke' }, () => { - beforeEach(() => { - cy.mockTradingPage(); - }); - - before(() => { - cy.setOnBoardingViewed(); - cy.mockTradingPage(MarketState.STATE_ACTIVE); - cy.mockSubscription(); - cy.visit('/#/markets/market-0'); - cy.wait('@Markets'); - cy.getByTestId(marketInfoBtn).click(); - cy.wait('@MarketInfo'); - }); - - it('current fees displayed', () => { - // 6002-MDET-101 - cy.getByTestId(marketTitle).contains('Current fees').click(); - validateMarketDataRow(0, 'Maker Fee', '0.02%'); - validateMarketDataRow(1, 'Infrastructure Fee', '0.05%'); - validateMarketDataRow(2, 'Liquidity Fee', '1.00%'); - validateMarketDataRow(3, 'Total Fees', '1.07%'); - }); - - it('market price', () => { - // 6002-MDET-102 - cy.getByTestId(marketTitle).contains('Market price').click(); - validateMarketDataRow(0, 'Mark Price', '46,126.90058'); - validateMarketDataRow(1, 'Best Bid Price', '44,126.90058 '); - validateMarketDataRow(2, 'Best Offer Price', '48,126.90058 '); - validateMarketDataRow(3, 'Quote Unit', 'BTC'); - }); - - it('market volume displayed', () => { - // 6002-MDET-103 - cy.getByTestId(marketTitle).contains('Market volume').click(); - validateMarketDataRow(1, 'Open Interest', '-'); - validateMarketDataRow(2, 'Best Bid Volume', '1'); - validateMarketDataRow(3, 'Best Offer Volume', '3'); - validateMarketDataRow(4, 'Best Static Bid Volume', '2'); - validateMarketDataRow(5, 'Best Static Offer Volume', '4'); - }); - - it('insurance pool displayed', () => { - // 6002-MDET-104 - cy.getByTestId(marketTitle).contains('Insurance pool').click(); - validateMarketDataRow(0, 'Balance', '0'); - }); - - it('key details displayed', () => { - // 6002-MDET-201 - cy.getByTestId(marketTitle).contains('Key details').click(); - - const rows: [string, string][] = compact([ - ['Name', 'BTCUSD Monthly (30 Jun 2022)'], - ['Market ID', 'market-0'], - Cypress.env('NX_SUCCESSOR_MARKETS') && ['Parent Market ID', 'PARENT-A'], - Cypress.env('NX_SUCCESSOR_MARKETS') && [ - 'Insurance Pool Fraction', - '0.75', - ], - ['Trading Mode', MarketTradingModeMapping.TRADING_MODE_CONTINUOUS], - ['Market Decimal Places', '5'], - ['Position Decimal Places', '0'], - ['Settlement Asset Decimal Places', '5'], - ]); - - for (const rowNumber in rows) { - const [name, value] = rows[rowNumber]; - validateMarketDataRow(Number(rowNumber), name, value); - } - }); - - it('instrument displayed', () => { - // 6002-MDET-202 - cy.getByTestId(marketTitle).contains('Instrument').click(); - - validateMarketDataRow(0, 'Market Name', 'BTCUSD Monthly (30 Jun 2022)'); - validateMarketDataRow(1, 'Code', 'BTCUSD.MF21'); - validateMarketDataRow(2, 'Product Type', 'Future'); - validateMarketDataRow(3, 'Quote Name', 'BTC'); - }); - - it('oracle displayed', () => { - // 6002-MDET-203 - cy.getByTestId(marketTitle).contains('Oracle').click(); - - cy.getByTestId(accordionContent) - .getByTestId(providerName) - .and('contain', 'Another oracle'); - - cy.getByTestId(providerName).should('be.visible').click(); - cy.getByTestId(dialogContent) - .eq(1) - .within(() => { - cy.getByTestId(blockExplorerLink).contains('Block explorer'); - cy.getByTestId(githubLink).contains('Oracle repository'); - }); - cy.getByTestId(dialogClose).click(); - - cy.getByTestId(accordionContent) - .getByTestId(verifiedProofs) - .and('contain', '1'); - }); - - it('settlement asset displayed', () => { - // 6002-MDET-206 - cy.getByTestId(marketTitle).contains('Settlement asset').click(); - cy.window().then((win) => { - cy.stub(win, 'prompt').returns('DISABLED WINDOW PROMPT'); - }); - validateMarketDataRow(0, 'ID', 'asset-id'); - validateMarketDataRow(1, 'Type', 'ERC20'); - validateMarketDataRow(2, 'Name', 'Euro'); - validateMarketDataRow(3, 'Symbol', 'tEURO'); - validateMarketDataRow(4, 'Decimals', '5'); - validateMarketDataRow(5, 'Quantum', '1'); - validateMarketDataRow(6, 'Status', 'Enabled'); - validateMarketDataRow(7, 'Contract address', '0x0158…78a4'); - validateMarketDataRow(8, 'Withdrawal threshold', '0.0005'); - validateMarketDataRow(9, 'Lifetime limit', '1,230'); - validateMarketDataRow(10, 'Infrastructure fee account balance', '0.00001'); - validateMarketDataRow(11, 'Global reward pool account balance', '0.00002'); - }); - - it('metadata displayed', () => { - // 6002-MDET-207 - cy.getByTestId(marketTitle).contains('Metadata').click(); - - validateMarketDataRow(0, 'Formerly', '076BB86A5AA41E3E'); - validateMarketDataRow(1, 'Base', 'BTC'); - validateMarketDataRow(2, 'Quote', 'USD'); - validateMarketDataRow(3, 'Class', 'fx/crypto'); - validateMarketDataRow(4, 'Sector', 'crypto'); - }); - - it('risk model displayed', () => { - // 6002-MDET-208 - cy.getByTestId(marketTitle).contains('Risk model').click(); - validateMarketDataRow(0, 'Tau', '0.0001140771161'); - validateMarketDataRow(1, 'Risk Aversion Parameter', '0.01'); - }); - - it('risk parameters displayed', () => { - // 6002-MDET-209 - cy.getByTestId(marketTitle).contains('Risk parameters').click(); - validateMarketDataRow(0, 'R', '0.016'); - validateMarketDataRow(1, 'Sigma', '0.3'); - }); - - it('risk factors displayed', () => { - // 6002-MDET-210 - cy.getByTestId(marketTitle).contains('Risk factors').click(); - - validateMarketDataRow(0, 'Short', '0.008571790367285281'); - validateMarketDataRow(1, 'Long', '0.008508132993273576'); - }); - - it('price monitoring bounds displayed', () => { - // 6002-MDET-211 - cy.getByTestId(marketTitle).contains('Price monitoring bounds 1').click(); - cy.get('p.col-span-1').contains('99.99999% probability price bounds'); - cy.get('p.col-span-1').contains('Within 43,200 seconds'); - validateMarketDataRow(0, 'Highest Price', '7.97323 '); - validateMarketDataRow(1, 'Lowest Price', '6.54701 '); - }); - - it('liquidity monitoring parameters displayed', () => { - // 6002-MDET-212 - cy.getByTestId(marketTitle) - .contains('Liquidity monitoring parameters') - .click(); - - validateMarketDataRow(0, 'Triggering Ratio', '0.7'); - validateMarketDataRow(1, 'Time Window', '3,600'); - validateMarketDataRow(2, 'Scaling Factor', '10'); - }); - - it('liquidity displayed', () => { - // 6002-MDET-213 - cy.getByTestId(marketTitle) - .contains(/Liquidity(?! m)/) - .click(); - - validateMarketDataRow(0, 'Target Stake', '10.00 tBTC'); - validateMarketDataRow(1, 'Supplied Stake', '0.01 tBTC'); - validateMarketDataRow(2, 'Market Value Proxy', '20.00 tBTC'); - cy.getByTestId(liquidityLink).should( - 'have.text', - 'View liquidity provision table' - ); - }); - - it('liquidity price range displayed', () => { - // 6002-MDET-214 - cy.getByTestId(marketTitle).contains('Liquidity price range').click(); - - validateMarketDataRow(0, 'Liquidity Price Range', '2.00% of mid price'); - validateMarketDataRow(1, 'Lowest Price', '45,204.362 BTC'); - validateMarketDataRow(2, 'Highest Price', '47,049.438 BTC'); - }); - - it('proposal displayed', () => { - // 6002-MDET-301 - cy.getByTestId(marketTitle).contains('Proposal').click(); - - cy.getByTestId(accordionContent) - .find(`[data-testid="${externalLink}"]`) - .first() - .should('have.text', 'View governance proposal') - .and('have.attr', 'href') - .and('contain', '/proposals/market-0'); - cy.getByTestId(accordionContent) - .find(`[data-testid="${externalLink}"]`) - .eq(1) - .should('have.text', 'Propose a change to market') - .and('have.attr', 'href') - .and('contain', '/proposals/propose/update-market'); - }); - - afterEach('close toggle', () => { - cy.get('[data-state="open"]').then((tab) => { - if (tab) tab.find('button').trigger('click'); - }); - }); - - function validateMarketDataRow( - rowNumber: number, - name: string, - value: string - ) { - cy.getByTestId(row) - .eq(rowNumber) - .within(() => { - cy.get('dt').should('contain.text', name); - cy.get('dd').should('contain.text', value); - }); - } -}); From 5596392835d1f3cb9539e5a3e5e3ed5d31b4f028 Mon Sep 17 00:00:00 2001 From: Joe Tsang <30622993+jtsang586@users.noreply.github.com> Date: Fri, 15 Sep 2023 13:04:42 +0100 Subject: [PATCH 24/31] chore(governance): fix failing staking test (#4801) --- apps/governance-e2e/src/integration/flow/staking-flow.cy.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/governance-e2e/src/integration/flow/staking-flow.cy.ts b/apps/governance-e2e/src/integration/flow/staking-flow.cy.ts index ef0160218..6a00b3d70 100644 --- a/apps/governance-e2e/src/integration/flow/staking-flow.cy.ts +++ b/apps/governance-e2e/src/integration/flow/staking-flow.cy.ts @@ -212,7 +212,7 @@ context( closeStakingDialog(); navigateTo(navigation.validators); cy.get(`[row-id="${0}"]`) - .eq(1) + .first() .within(() => { cy.getByTestId(stakeValidatorListTotalStake) .should('have.text', '3,002.00') @@ -222,7 +222,7 @@ context( .and('be.visible'); }); cy.get(`[row-id="${1}"]`) - .eq(1) + .first() .within(() => { cy.getByTestId(stakeValidatorListTotalStake) .scrollIntoView() From e944d3e37c86183943549b3c7bcd45196bf86451 Mon Sep 17 00:00:00 2001 From: Matthew Russell Date: Fri, 15 Sep 2023 05:12:39 -0700 Subject: [PATCH 25/31] fix(trading): correct link for get started prompt (#4782) --- apps/trading/components/welcome-dialog/get-started.tsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/apps/trading/components/welcome-dialog/get-started.tsx b/apps/trading/components/welcome-dialog/get-started.tsx index c496a5f55..9a4f1503d 100644 --- a/apps/trading/components/welcome-dialog/get-started.tsx +++ b/apps/trading/components/welcome-dialog/get-started.tsx @@ -73,7 +73,6 @@ export const GetStarted = ({ lead }: Props) => { const openVegaWalletDialog = useVegaWalletDialogStore( (store) => store.openVegaWalletDialog ); - const CANONICAL_URL = VEGA_NETWORKS[VEGA_ENV] || 'https://console.vega.xyz'; const currentStep = useGetOnboardingStep(); const dismissed = useOnboardingStore((store) => store.dismissed); @@ -116,7 +115,7 @@ export const GetStarted = ({ lead }: Props) => { {VEGA_ENV === Networks.MAINNET && (

    {t('Experiment for free with virtual assets on')}{' '} - + {t('Fairground Testnet')}

    @@ -124,7 +123,7 @@ export const GetStarted = ({ lead }: Props) => { {VEGA_ENV === Networks.TESTNET && (

    {t('Ready to trade with real funds?')}{' '} - + {t('Switch to Mainnet')}

    From 3de5b07495ed16308372d2710952c181fe3d8bc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20G=C5=82ownia?= Date: Fri, 15 Sep 2023 14:13:05 +0200 Subject: [PATCH 26/31] fix(trading): add overflow hidden to candles tab container (#4803) --- apps/trading/client-pages/market/trade-grid.tsx | 1 + libs/ui-toolkit/src/components/tabs/tabs.tsx | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/trading/client-pages/market/trade-grid.tsx b/apps/trading/client-pages/market/trade-grid.tsx index ab64f77b1..39a2e4723 100644 --- a/apps/trading/client-pages/market/trade-grid.tsx +++ b/apps/trading/client-pages/market/trade-grid.tsx @@ -56,6 +56,7 @@ const MainGrid = memo( } > diff --git a/libs/ui-toolkit/src/components/tabs/tabs.tsx b/libs/ui-toolkit/src/components/tabs/tabs.tsx index d20720556..69b8c3e1b 100644 --- a/libs/ui-toolkit/src/components/tabs/tabs.tsx +++ b/libs/ui-toolkit/src/components/tabs/tabs.tsx @@ -113,7 +113,9 @@ export const Tabs = ({ return ( {child.props.children} @@ -131,6 +133,7 @@ interface TabProps { name: string; indicator?: ReactNode; hidden?: boolean; + overflowHidden?: boolean; menu?: ReactNode; } From 78afecc2e51409f3973b20450d09e5b2e75d23e5 Mon Sep 17 00:00:00 2001 From: Matthew Russell Date: Fri, 15 Sep 2023 05:24:47 -0700 Subject: [PATCH 27/31] chore(trading): layout adjustments to accomodate default 13 inch screens (#4798) --- .../client-pages/market/trade-grid.tsx | 4 +- .../layouts/layout-with-sidebar.tsx | 3 +- apps/trading/pages/styles.css | 24 ++++--- libs/candles-chart/src/lib/candles-chart.tsx | 62 ++++++++++--------- .../src/lib/use-candles-chart-settings.ts | 2 +- 5 files changed, 54 insertions(+), 41 deletions(-) diff --git a/apps/trading/client-pages/market/trade-grid.tsx b/apps/trading/client-pages/market/trade-grid.tsx index 39a2e4723..79433a3b1 100644 --- a/apps/trading/client-pages/market/trade-grid.tsx +++ b/apps/trading/client-pages/market/trade-grid.tsx @@ -73,7 +73,7 @@ const MainGrid = memo( @@ -181,7 +181,7 @@ const TradeGridChild = ({ children }: TradeGridChildProps) => { {({ width, height }) => (
    {children}
    diff --git a/apps/trading/components/layouts/layout-with-sidebar.tsx b/apps/trading/components/layouts/layout-with-sidebar.tsx index e9558833f..d8c3a461e 100644 --- a/apps/trading/components/layouts/layout-with-sidebar.tsx +++ b/apps/trading/components/layouts/layout-with-sidebar.tsx @@ -13,7 +13,8 @@ export const LayoutWithSidebar = () => { 'h-full relative z-0 grid', 'grid-rows-[min-content_1fr_40px]', 'lg:grid-rows-[min-content_1fr]', - 'lg:grid-cols-[1fr_350px_40px]' + 'lg:grid-cols-[1fr_280px_40px]', + 'xxxl:grid-cols-[1fr_320px_40px]' ); return ( diff --git a/apps/trading/pages/styles.css b/apps/trading/pages/styles.css index e4e2d4659..7d4f32462 100644 --- a/apps/trading/pages/styles.css +++ b/apps/trading/pages/styles.css @@ -83,8 +83,7 @@ html [data-theme='light'] { --pennant-color-volume-sell: theme(colors.market.red.DEFAULT); /* reduce space between candles */ - --pennant-candlestick-inner-padding: 0.175; - --pennant-candlestick-stroke-width: 0.5; + --pennant-candlestick-inner-padding: 0.25; } html [data-theme='light'] { @@ -162,11 +161,22 @@ html [data-theme='dark'] { @apply font-normal font-alpha; } -/* Light variables */ -.ag-theme-balham { +.ag-theme-balham, +.ag-theme-balham-dark { --ag-grid-size: 2px; /* Used for compactness */ --ag-row-height: 36px; - --ag-header-height: 36px; + --ag-header-height: 28px; +} + +@media (min-width: theme(screens.xxl)) { + .ag-theme-balham, + .ag-theme-balham-dark { + --ag-header-height: 36px; + } +} + +/* Light variables */ +.ag-theme-balham { --ag-background-color: theme(colors.white); --ag-border-color: theme(colors.vega.clight.600); --ag-header-background-color: theme(colors.vega.clight.700); @@ -179,9 +189,6 @@ html [data-theme='dark'] { /* Dark variables */ .ag-theme-balham-dark { - --ag-grid-size: 2px; /* Used for compactness */ - --ag-row-height: 36px; - --ag-header-height: 36px; --ag-background-color: theme(colors.vega.cdark.900); --ag-border-color: theme(colors.vega.cdark.600); --ag-header-background-color: theme(colors.vega.cdark.700); @@ -191,6 +198,7 @@ html [data-theme='dark'] { --ag-row-hover-color: theme(colors.vega.cdark.800); --ag-modal-overlay-background-color: rgb(9 11 16 / 50%); } + .ag-theme-balham-dark .ag-row.no-hover, .ag-theme-balham-dark .ag-row.no-hover:hover, .ag-theme-balham .ag-row.no-hover, diff --git a/libs/candles-chart/src/lib/candles-chart.tsx b/libs/candles-chart/src/lib/candles-chart.tsx index c0397f681..aeb1e4091 100644 --- a/libs/candles-chart/src/lib/candles-chart.tsx +++ b/libs/candles-chart/src/lib/candles-chart.tsx @@ -8,13 +8,16 @@ import AutoSizer from 'react-virtualized-auto-sizer'; import { useVegaWallet } from '@vegaprotocol/wallet'; import { useThemeSwitcher } from '@vegaprotocol/react-helpers'; import { t } from '@vegaprotocol/i18n'; -import { useCandlesChartSettings } from './use-candles-chart-settings'; +import { + STUDY_SIZE, + useCandlesChartSettings, +} from './use-candles-chart-settings'; export type CandlesChartContainerProps = { marketId: string; }; -const CANDLES_TO_WIDTH_FACTOR = 0.15; +const CANDLES_TO_WIDTH_FACTOR = 0.2; export const CandlesChartContainer = ({ marketId, @@ -49,33 +52,34 @@ export const CandlesChartContainer = ({ return ( - {({ width, height }) => ( -
    - {t('No data')} - ), - initialNumCandlesToDisplay: Math.floor( - width * CANDLES_TO_WIDTH_FACTOR - ), - studySize: 150, // default size - studySizes, - }} - interval={interval} - theme={theme} - onOptionsChanged={(options) => { - setStudies(options.studies); - setOverlays(options.overlays); - }} - onPaneChanged={handlePaneChange} - /> -
    - )} + {({ width, height }) => { + const candlesCount = Math.floor(width * CANDLES_TO_WIDTH_FACTOR); + return ( +
    + {t('No data')} + ), + initialNumCandlesToDisplay: candlesCount, + studySize: STUDY_SIZE, + studySizes, + }} + interval={interval} + theme={theme} + onOptionsChanged={(options) => { + setStudies(options.studies); + setOverlays(options.overlays); + }} + onPaneChanged={handlePaneChange} + /> +
    + ); + }}
    ); }; diff --git a/libs/candles-chart/src/lib/use-candles-chart-settings.ts b/libs/candles-chart/src/lib/use-candles-chart-settings.ts index c43ab4732..053101892 100644 --- a/libs/candles-chart/src/lib/use-candles-chart-settings.ts +++ b/libs/candles-chart/src/lib/use-candles-chart-settings.ts @@ -15,7 +15,7 @@ interface StoredSettings { studySizes: StudySizes; } -export const STUDY_SIZE = 100; +export const STUDY_SIZE = 90; const STUDY_ORDER: Study[] = [ Study.FORCE_INDEX, Study.RELATIVE_STRENGTH_INDEX, From 6d35f2b39dac8b046bba6122f7d82d83d9f0ba6b Mon Sep 17 00:00:00 2001 From: Maciek Date: Fri, 15 Sep 2023 14:36:08 +0200 Subject: [PATCH 28/31] chore(trading): 4764 remember closed sidebar (#4799) Co-authored-by: Madalina Raicu --- .../trading-e2e/src/integration/deposit.cy.ts | 2 +- apps/trading/client-pages/market/market.tsx | 16 ++--- .../client-pages/portfolio/portfolio.tsx | 12 ++-- .../accounts-container/accounts-container.tsx | 10 ++-- .../accounts-menu/accounts-menu.tsx | 8 ++- .../deposits-menu/deposits-menu.tsx | 6 +- .../layouts/layout-with-sidebar.tsx | 6 +- .../orderbook-container.tsx | 6 +- .../components/sidebar/sidebar.spec.tsx | 34 ++++++++--- apps/trading/components/sidebar/sidebar.tsx | 58 +++++++++++-------- .../vega-wallet-connect-button.spec.tsx | 4 ++ .../vega-wallet-connect-button.tsx | 6 +- .../vega-wallet/vega-wallet-menu.tsx | 6 +- .../components/welcome-dialog/get-started.tsx | 6 +- .../withdrawals-menu/withdrawals-menu.tsx | 7 ++- .../lib/hooks/use-get-current-route-id.ts | 15 +++++ apps/trading/pages/client-router.tsx | 7 ++- 17 files changed, 141 insertions(+), 68 deletions(-) create mode 100644 apps/trading/lib/hooks/use-get-current-route-id.ts diff --git a/apps/trading-e2e/src/integration/deposit.cy.ts b/apps/trading-e2e/src/integration/deposit.cy.ts index ab2858c40..b1947c2d6 100644 --- a/apps/trading-e2e/src/integration/deposit.cy.ts +++ b/apps/trading-e2e/src/integration/deposit.cy.ts @@ -104,7 +104,7 @@ describe('deposit actions', { tags: '@smoke' }, () => { cy.visit('/#/markets/market-1'); }); - it('Deposit to trade is visible', () => { + it.skip('Deposit to trade is visible', () => { cy.getByTestId('Collateral').click(); cy.get('[row-id="asset-id"]').contains('tEURO').should('be.visible'); cy.contains('[data-testid="deposit"]', 'Deposit').should('be.visible'); diff --git a/apps/trading/client-pages/market/market.tsx b/apps/trading/client-pages/market/market.tsx index 72bad717e..05f8a3159 100644 --- a/apps/trading/client-pages/market/market.tsx +++ b/apps/trading/client-pages/market/market.tsx @@ -11,6 +11,7 @@ import { TradePanels } from './trade-panels'; import { useNavigate, useParams } from 'react-router-dom'; import { Links, Routes } from '../../pages/client-router'; import { ViewType, useSidebar } from '../../components/sidebar'; +import { useGetCurrentRouteId } from '../../lib/hooks/use-get-current-route-id'; const calculatePrice = (markPrice?: string, decimalPlaces?: number) => { return markPrice && decimalPlaces @@ -58,7 +59,9 @@ const TitleUpdater = ({ export const MarketPage = () => { const { marketId } = useParams(); const navigate = useNavigate(); - const { init, view, setView } = useSidebar(); + const currentRouteId = useGetCurrentRouteId(); + const { setViews, getView } = useSidebar(); + const view = getView(currentRouteId); const { screenSize } = useScreenDimensions(); const largeScreen = ['lg', 'xl', 'xxl', 'xxxl'].includes(screenSize); const update = useGlobalStore((store) => store.update); @@ -69,15 +72,14 @@ export const MarketPage = () => { useEffect(() => { if (data?.id && data.id !== lastMarketId) { update({ marketId: data.id }); - // make sidebar open on market id change - setView({ type: ViewType.Order }); } + }, [update, lastMarketId, data?.id]); - // make sidebar open on deal ticket by default - if (view === null) { - setView({ type: ViewType.Order }); + useEffect(() => { + if (largeScreen && view === undefined) { + setViews({ type: ViewType.Order }, currentRouteId); } - }, [update, lastMarketId, data?.id, setView, init, view]); + }, [setViews, view, currentRouteId, largeScreen]); const tradeView = useMemo(() => { if (largeScreen) { diff --git a/apps/trading/client-pages/portfolio/portfolio.tsx b/apps/trading/client-pages/portfolio/portfolio.tsx index 5fb0c0b38..e33348f11 100644 --- a/apps/trading/client-pages/portfolio/portfolio.tsx +++ b/apps/trading/client-pages/portfolio/portfolio.tsx @@ -23,6 +23,7 @@ import { ViewType, useSidebar } from '../../components/sidebar'; import { AccountsMenu } from '../../components/accounts-menu'; import { DepositsMenu } from '../../components/deposits-menu'; import { WithdrawalsMenu } from '../../components/withdrawals-menu'; +import { useGetCurrentRouteId } from '../../lib/hooks/use-get-current-route-id'; const WithdrawalsIndicator = () => { const { ready } = useIncompleteWithdrawals(); @@ -37,7 +38,10 @@ const WithdrawalsIndicator = () => { }; export const Portfolio = () => { - const { init, view, setView } = useSidebar(); + const currentRouteId = useGetCurrentRouteId(); + const { getView, setViews } = useSidebar(); + const view = getView(currentRouteId); + const { updateTitle } = usePageTitleStore((store) => ({ updateTitle: store.updateTitle, })); @@ -48,10 +52,10 @@ export const Portfolio = () => { // Make transfer sidebar open by default useEffect(() => { - if (init && view === null) { - setView({ type: ViewType.Transfer }); + if (view === undefined) { + setViews({ type: ViewType.Transfer }, currentRouteId); } - }, [init, view, setView]); + }, [view, setViews, currentRouteId]); const [sizes, handleOnLayoutChange] = usePaneLayout({ id: 'portfolio' }); const wrapperClasses = 'p-0.5 h-full max-h-full flex flex-col'; diff --git a/apps/trading/components/accounts-container/accounts-container.tsx b/apps/trading/components/accounts-container/accounts-container.tsx index 73f2d04a4..9574fa9f1 100644 --- a/apps/trading/components/accounts-container/accounts-container.tsx +++ b/apps/trading/components/accounts-container/accounts-container.tsx @@ -12,6 +12,7 @@ import type { DataGridSlice } from '../../stores/datagrid-store-slice'; import { createDataGridSlice } from '../../stores/datagrid-store-slice'; import { ViewType, useSidebar } from '../sidebar'; import { useMarketClickHandler } from '../../lib/hooks/use-market-click-handler'; +import { useGetCurrentRouteId } from '../../lib/hooks/use-get-current-route-id'; export const AccountsContainer = ({ pinnedAsset, @@ -21,7 +22,8 @@ export const AccountsContainer = ({ const onMarketClick = useMarketClickHandler(true); const { pubKey, isReadOnly } = useVegaWallet(); const { open: openAssetDetailsDialog } = useAssetDetailsDialogStore(); - const setView = useSidebar((store) => store.setView); + const currentRouteId = useGetCurrentRouteId(); + const setViews = useSidebar((store) => store.setViews); const gridStore = useAccountStore((store) => store.gridStore); const updateGridStore = useAccountStore((store) => store.updateGridStore); @@ -49,13 +51,13 @@ export const AccountsContainer = ({ partyId={pubKey} onClickAsset={onClickAsset} onClickWithdraw={(assetId) => { - setView({ type: ViewType.Withdraw, assetId }); + setViews({ type: ViewType.Withdraw, assetId }, currentRouteId); }} onClickDeposit={(assetId) => { - setView({ type: ViewType.Deposit, assetId }); + setViews({ type: ViewType.Deposit, assetId }, currentRouteId); }} onClickTransfer={(assetId) => { - setView({ type: ViewType.Transfer, assetId }); + setViews({ type: ViewType.Transfer, assetId }, currentRouteId); }} onMarketClick={onMarketClick} isReadOnly={isReadOnly} diff --git a/apps/trading/components/accounts-menu/accounts-menu.tsx b/apps/trading/components/accounts-menu/accounts-menu.tsx index 86c80e91c..8bfed5d76 100644 --- a/apps/trading/components/accounts-menu/accounts-menu.tsx +++ b/apps/trading/components/accounts-menu/accounts-menu.tsx @@ -1,22 +1,24 @@ import { t } from '@vegaprotocol/i18n'; import { TradingButton } from '@vegaprotocol/ui-toolkit'; import { ViewType, useSidebar } from '../sidebar'; +import { useGetCurrentRouteId } from '../../lib/hooks/use-get-current-route-id'; export const AccountsMenu = () => { - const setView = useSidebar((store) => store.setView); + const currentRouteId = useGetCurrentRouteId(); + const setViews = useSidebar((store) => store.setViews); return ( <> setView({ type: ViewType.Transfer })} + onClick={() => setViews({ type: ViewType.Transfer }, currentRouteId)} > {t('Transfer')} setView({ type: ViewType.Deposit })} + onClick={() => setViews({ type: ViewType.Deposit }, currentRouteId)} > {t('Deposit')} diff --git a/apps/trading/components/deposits-menu/deposits-menu.tsx b/apps/trading/components/deposits-menu/deposits-menu.tsx index 81b6edf60..d67225692 100644 --- a/apps/trading/components/deposits-menu/deposits-menu.tsx +++ b/apps/trading/components/deposits-menu/deposits-menu.tsx @@ -1,14 +1,16 @@ import { t } from '@vegaprotocol/i18n'; import { TradingButton } from '@vegaprotocol/ui-toolkit'; import { ViewType, useSidebar } from '../sidebar'; +import { useGetCurrentRouteId } from '../../lib/hooks/use-get-current-route-id'; export const DepositsMenu = () => { - const setView = useSidebar((store) => store.setView); + const currentRouteId = useGetCurrentRouteId(); + const setViews = useSidebar((store) => store.setViews); return ( setView({ type: ViewType.Deposit })} + onClick={() => setViews({ type: ViewType.Deposit }, currentRouteId)} data-testid="deposit-button" > {t('Deposit')} diff --git a/apps/trading/components/layouts/layout-with-sidebar.tsx b/apps/trading/components/layouts/layout-with-sidebar.tsx index d8c3a461e..0e777b993 100644 --- a/apps/trading/components/layouts/layout-with-sidebar.tsx +++ b/apps/trading/components/layouts/layout-with-sidebar.tsx @@ -4,11 +4,13 @@ import classNames from 'classnames'; import { Routes as AppRoutes } from '../../pages/client-router'; import { MarketHeader } from '../market-header'; import { LiquidityHeader } from '../liquidity-header'; +import { useGetCurrentRouteId } from '../../lib/hooks/use-get-current-route-id'; export const LayoutWithSidebar = () => { - const sidebarView = useSidebar((store) => store.view); + const currentRouteId = useGetCurrentRouteId(); + const views = useSidebar((store) => store.views); + const sidebarView = views[currentRouteId] || null; const sidebarOpen = sidebarView !== null; - const gridClasses = classNames( 'h-full relative z-0 grid', 'grid-rows-[min-content_1fr_40px]', diff --git a/apps/trading/components/orderbook-container/orderbook-container.tsx b/apps/trading/components/orderbook-container/orderbook-container.tsx index 07b0eb7ca..f2fdc53c6 100644 --- a/apps/trading/components/orderbook-container/orderbook-container.tsx +++ b/apps/trading/components/orderbook-container/orderbook-container.tsx @@ -1,16 +1,18 @@ import { OrderbookManager } from '@vegaprotocol/market-depth'; import { ViewType, useSidebar } from '../sidebar'; import { useDealTicketFormValues } from '@vegaprotocol/deal-ticket'; +import { useGetCurrentRouteId } from '../../lib/hooks/use-get-current-route-id'; export const OrderbookContainer = ({ marketId }: { marketId: string }) => { + const currentRouteId = useGetCurrentRouteId(); const update = useDealTicketFormValues((state) => state.updateAll); - const setView = useSidebar((store) => store.setView); + const setViews = useSidebar((store) => store.setViews); return ( { update(marketId, values); - setView({ type: ViewType.Order }); + setViews({ type: ViewType.Order }, currentRouteId); }} /> ); diff --git a/apps/trading/components/sidebar/sidebar.spec.tsx b/apps/trading/components/sidebar/sidebar.spec.tsx index 5867d6525..5a78360c3 100644 --- a/apps/trading/components/sidebar/sidebar.spec.tsx +++ b/apps/trading/components/sidebar/sidebar.spec.tsx @@ -11,6 +11,7 @@ import { MemoryRouter, Route, Routes } from 'react-router-dom'; import { VegaIconNames } from '@vegaprotocol/ui-toolkit'; import type { VegaWalletContextShape } from '@vegaprotocol/wallet'; import { VegaWalletContext } from '@vegaprotocol/wallet'; +import { Routes as AppRoutes } from '../../pages/client-router'; jest.mock('../node-health', () => ({ NodeHealthContainer: () => , @@ -115,7 +116,11 @@ describe('SidebarContent', () => { - } /> + } + /> @@ -124,13 +129,17 @@ describe('SidebarContent', () => { expect(container).toBeEmptyDOMElement(); act(() => { - useSidebar.setState({ view: { type: ViewType.Transfer } }); + useSidebar.setState({ + views: { [AppRoutes.MARKET]: { type: ViewType.Transfer } }, + }); }); expect(screen.getByTestId('transfer')).toBeInTheDocument(); act(() => { - useSidebar.setState({ view: { type: ViewType.Deposit } }); + useSidebar.setState({ + views: { [AppRoutes.MARKET]: { type: ViewType.Deposit } }, + }); }); expect(screen.getByTestId('deposit')).toBeInTheDocument(); @@ -141,26 +150,36 @@ describe('SidebarContent', () => { - } /> + } + /> ); act(() => { - useSidebar.setState({ view: { type: ViewType.Order } }); + useSidebar.setState({ + views: { [AppRoutes.PORTFOLIO]: { type: ViewType.Order } }, + }); }); expect(container).toBeEmptyDOMElement(); act(() => { - useSidebar.setState({ view: { type: ViewType.Settings } }); + useSidebar.setState({ + views: { [AppRoutes.PORTFOLIO]: { type: ViewType.Settings } }, + }); }); expect(screen.getByTestId('settings')).toBeInTheDocument(); act(() => { - useSidebar.setState({ view: { type: ViewType.Info } }); + useSidebar.setState({ + views: { [AppRoutes.PORTFOLIO]: { type: ViewType.Info } }, + }); }); expect(container).toBeEmptyDOMElement(); @@ -178,6 +197,7 @@ describe('SidebarButton', () => { tooltip="INFO" onClick={onClick} view={view} + routeId="current-route-id" /> ); diff --git a/apps/trading/components/sidebar/sidebar.tsx b/apps/trading/components/sidebar/sidebar.tsx index d32d0d8d0..fcfc9ff4b 100644 --- a/apps/trading/components/sidebar/sidebar.tsx +++ b/apps/trading/components/sidebar/sidebar.tsx @@ -16,6 +16,7 @@ import { WithdrawContainer } from '../withdraw-container'; import { Routes as AppRoutes } from '../../pages/client-router'; import { GetStarted } from '../welcome-dialog'; import { useVegaWallet, useViewAsDialog } from '@vegaprotocol/wallet'; +import { useGetCurrentRouteId } from '../../lib/hooks/use-get-current-route-id'; export enum ViewType { Order = 'Order', @@ -51,6 +52,7 @@ type SidebarView = }; export const Sidebar = () => { + const currentRouteId = useGetCurrentRouteId(); const navClasses = 'flex lg:flex-col items-center gap-2 lg:gap-4 p-1'; const setViewAsDialogOpen = useViewAsDialog((state) => state.setOpen); const { pubKeys } = useVegaWallet(); @@ -62,16 +64,19 @@ export const Sidebar = () => { view={ViewType.Deposit} icon={VegaIconNames.DEPOSIT} tooltip={t('Deposit')} + routeId={currentRouteId} /> {/* buttons for specific routes */} @@ -94,11 +99,13 @@ export const Sidebar = () => { view={ViewType.Order} icon={VegaIconNames.TICKET} tooltip={t('Order')} + routeId={currentRouteId} /> } @@ -114,12 +121,13 @@ export const Sidebar = () => { icon={VegaIconNames.EYE} tooltip={t('View as party')} disabled={Boolean(pubKeys)} + routeId={currentRouteId} /> - @@ -133,23 +141,25 @@ export const SidebarButton = ({ tooltip, disabled = false, onClick, + routeId, }: { view?: ViewType; icon: VegaIconNames; tooltip: string; disabled?: boolean; onClick?: () => void; + routeId: string; }) => { - const { currView, setView } = useSidebar((store) => ({ - currView: store.view, - setView: store.setView, + const { setViews, getView } = useSidebar((store) => ({ + setViews: store.setViews, + getView: store.getView, })); - + const currView = getView(routeId); const onSelect = (view: SidebarView['type']) => { if (view === currView?.type) { - setView(null); + setViews(null, routeId); } else { - setView({ type: view }); + setViews({ type: view }, routeId); } }; @@ -195,8 +205,10 @@ const SidebarDivider = () => { export const SidebarContent = () => { const params = useParams(); - const { view, setView } = useSidebar(); + const currentRouteId = useGetCurrentRouteId(); + const { setViews, getView } = useSidebar(); + const view = getView(currentRouteId); if (!view) return null; if (view.type === ViewType.Order) { @@ -206,7 +218,7 @@ export const SidebarContent = () => { - setView({ type: ViewType.Deposit, assetId }) + setViews({ type: ViewType.Deposit, assetId }, currentRouteId) } /> @@ -288,25 +300,21 @@ const ContentWrapper = ({ /** If rendered will close sidebar */ const CloseSidebar = () => { - const setView = useSidebar((store) => store.setView); + const currentRouteId = useGetCurrentRouteId(); + const setViews = useSidebar((store) => store.setViews); useEffect(() => { - setView(null); - }, [setView]); + setViews(null, currentRouteId); + }, [setViews, currentRouteId]); return null; }; export const useSidebar = create<{ - init: boolean; - view: SidebarView | null; - setView: (view: SidebarView | null) => void; -}>()((set) => ({ - init: true, - view: null, - setView: (x) => - set(() => { - if (x == null) { - return { view: null, init: false }; - } - return { view: x, init: false }; - }), + views: { [key: string]: SidebarView | null }; + setViews: (view: SidebarView | null, routeId: string) => void; + getView: (routeId: string) => SidebarView | null | undefined; +}>()((set, get) => ({ + views: {}, + setViews: (x, routeId) => + set(({ views }) => ({ views: { ...views, [routeId]: x } })), + getView: (routeId) => get().views[routeId], })); diff --git a/apps/trading/components/vega-wallet-connect-button/vega-wallet-connect-button.spec.tsx b/apps/trading/components/vega-wallet-connect-button/vega-wallet-connect-button.spec.tsx index b572323a1..ed4eb9af5 100644 --- a/apps/trading/components/vega-wallet-connect-button/vega-wallet-connect-button.spec.tsx +++ b/apps/trading/components/vega-wallet-connect-button/vega-wallet-connect-button.spec.tsx @@ -11,6 +11,10 @@ jest.mock('@vegaprotocol/wallet', () => ({ useVegaWalletDialogStore: () => mockUpdateDialogOpen, })); +jest.mock('../../lib/hooks/use-get-current-route-id', () => ({ + useGetCurrentRouteId: jest.fn().mockReturnValue('current-route-id'), +})); + beforeEach(() => { jest.clearAllMocks(); }); diff --git a/apps/trading/components/vega-wallet-connect-button/vega-wallet-connect-button.tsx b/apps/trading/components/vega-wallet-connect-button/vega-wallet-connect-button.tsx index 0a1bb8f80..1d47dc692 100644 --- a/apps/trading/components/vega-wallet-connect-button/vega-wallet-connect-button.tsx +++ b/apps/trading/components/vega-wallet-connect-button/vega-wallet-connect-button.tsx @@ -22,13 +22,15 @@ import { useVegaWallet, useVegaWalletDialogStore } from '@vegaprotocol/wallet'; import { useCopyTimeout } from '@vegaprotocol/react-helpers'; import { ViewType, useSidebar } from '../sidebar'; import classNames from 'classnames'; +import { useGetCurrentRouteId } from '../../lib/hooks/use-get-current-route-id'; export const VegaWalletConnectButton = () => { const [dropdownOpen, setDropdownOpen] = useState(false); const openVegaWalletDialog = useVegaWalletDialogStore( (store) => store.openVegaWalletDialog ); - const setView = useSidebar((store) => store.setView); + const currentRouteId = useGetCurrentRouteId(); + const setViews = useSidebar((store) => store.setViews); const { pubKey, pubKeys, @@ -95,7 +97,7 @@ export const VegaWalletConnectButton = () => { { - setView({ type: ViewType.Transfer }); + setViews({ type: ViewType.Transfer }, currentRouteId); setDropdownOpen(false); }} > diff --git a/apps/trading/components/vega-wallet/vega-wallet-menu.tsx b/apps/trading/components/vega-wallet/vega-wallet-menu.tsx index 8e3f9d75c..089082e88 100644 --- a/apps/trading/components/vega-wallet/vega-wallet-menu.tsx +++ b/apps/trading/components/vega-wallet/vega-wallet-menu.tsx @@ -10,6 +10,7 @@ import { useVegaWallet, type PubKey } from '@vegaprotocol/wallet'; import { useCallback, useMemo } from 'react'; import CopyToClipboard from 'react-copy-to-clipboard'; import { ViewType, useSidebar } from '../sidebar'; +import { useGetCurrentRouteId } from '../../lib/hooks/use-get-current-route-id'; export const VegaWalletMenu = ({ setMenu, @@ -17,7 +18,8 @@ export const VegaWalletMenu = ({ setMenu: (open: 'nav' | 'wallet' | null) => void; }) => { const { pubKey, pubKeys, selectPubKey, disconnect } = useVegaWallet(); - const setView = useSidebar((store) => store.setView); + const currentRouteId = useGetCurrentRouteId(); + const setViews = useSidebar((store) => store.setViews); const activeKey = useMemo(() => { return pubKeys?.find((pk) => pk.publicKey === pubKey); @@ -46,7 +48,7 @@ export const VegaWalletMenu = ({