diff --git a/README.md b/README.md index 5584a17d9..9892cd2f8 100644 --- a/README.md +++ b/README.md @@ -47,11 +47,11 @@ For shared Cypress logic, commands and steps. ### [Web3](./libs/web3) -A ulitity library for connecting to the Ethereum network and interacting with Vega Web3 contracts. +A utility library for connecting to the Ethereum network and interacting with Vega Web3 contracts. ### [React Helpers](./libs/react-helpers) -Generic react helpers that can be used across multilpe applications, along with other utilties. +Generic react helpers that can be used across multilpe applications, along with other utilities. # 💻 Develop @@ -107,7 +107,7 @@ Visit the [Nx Documentation](https://nx.dev/getting-started/intro) to learn more ## Docker -The [Dockerfile](./Dockerfile) for running the frontends is pretty basic, merely building the application with the APP arg that is passed in and serving the application from [nginx](./nginx/nginx.conf). The only complexity that exists is that there is a script which allows the passing of run time environement variabels to the containers. See configuration below for how to do this. +The [Dockerfile](./Dockerfile) for running the frontends is pretty basic, merely building the application with the APP arg that is passed in and serving the application from [nginx](./nginx/nginx.conf). The only complexity that exists is that there is a script which allows the passing of run time environment variables to the containers. See configuration below for how to do this. You can build any of the containers locally with the following command: @@ -123,7 +123,7 @@ docker run -p 3000:80 [TAG] ## Config -As envrionment variabels are build time and not run time in frontend applications. We have built a system which allows for passing run time environment variables, this generates a JSON file that will override the default environement vairbales that the container was built with (which is always testnet, using the default .env files). +As environment variables are build time and not run time in frontend applications. We have built a system which allows for passing run time environment variables, this generates a JSON file that will override the default environment variables that the container was built with (which is always testnet, using the default .env files). In order to override specific environment variables you can pass these to the container like this: @@ -137,7 +137,7 @@ Which will now point the app to use a devnet data node. To see a list of all pos Coming soon! You will be able to run the containers within Vega Capsule. -You can run against a local intance of Vega Cpasule today by using the .env.capsule present in the apps. +You can run against a local instance of Vega Capsule today by using the .env.capsule present in the apps. # 📑 License diff --git a/apps/explorer/src/app/routes/network-parameters/network-parameters.test.tsx b/apps/explorer/src/app/routes/network-parameters/network-parameters.spec.tsx similarity index 91% rename from apps/explorer/src/app/routes/network-parameters/network-parameters.test.tsx rename to apps/explorer/src/app/routes/network-parameters/network-parameters.spec.tsx index db966e9dc..7d9f3445e 100644 --- a/apps/explorer/src/app/routes/network-parameters/network-parameters.test.tsx +++ b/apps/explorer/src/app/routes/network-parameters/network-parameters.spec.tsx @@ -24,10 +24,10 @@ describe('NetworkParametersTable', () => { ); const rows = screen.getAllByTestId('key-value-table-row'); expect(rows[0].children[0]).toHaveTextContent( - 'market.fee.factors.infrastructureFee' + 'Market Fee Factors Infrastructure Fee' ); expect(rows[1].children[0]).toHaveTextContent( - 'market.liquidityProvision.minLpStakeQuantumMultiple' + 'Market Liquidity Provision Min Lp Stake Quantum Multiple' ); expect(rows[0].children[1]).toHaveTextContent('0.0005'); expect(rows[1].children[1]).toHaveTextContent('1'); @@ -54,10 +54,10 @@ describe('NetworkParametersTable', () => { ); const rows = screen.getAllByTestId('key-value-table-row'); expect(rows[0].children[0]).toHaveTextContent( - 'market.fee.factors.infrastructureFee' + 'Market Fee Factors Infrastructure Fee' ); expect(rows[1].children[0]).toHaveTextContent( - 'market.liquidityProvision.minLpStakeQuantumMultiple' + 'Market Liquidity Provision Min Lp Stake Quantum Multiple' ); expect(rows[0].children[1]).toHaveTextContent('0.0005'); expect(rows[1].children[1]).toHaveTextContent('1'); diff --git a/apps/explorer/src/app/routes/network-parameters/network-parameters.tsx b/apps/explorer/src/app/routes/network-parameters/network-parameters.tsx index 2956ed263..47c859ebb 100644 --- a/apps/explorer/src/app/routes/network-parameters/network-parameters.tsx +++ b/apps/explorer/src/app/routes/network-parameters/network-parameters.tsx @@ -16,6 +16,7 @@ import type { NetworkParametersQuery_networkParameters, } from './__generated__/NetworkParametersQuery'; import orderBy from 'lodash/orderBy'; +import startCase from 'lodash/startCase'; const BIG_NUMBER_PARAMS = [ 'spam.protection.delegation.min.tokens', @@ -42,7 +43,7 @@ export const renderRow = ({ const isSyntaxRow = isJsonObject(value); return ( - {key} + {startCase(key)} {isSyntaxRow ? ( ) : isNaN(Number(value)) ? ( diff --git a/apps/trading-e2e/src/support/mocks/generate-deal-ticket-query.ts b/apps/trading-e2e/src/support/mocks/generate-deal-ticket-query.ts index 58b3764c8..14626634b 100644 --- a/apps/trading-e2e/src/support/mocks/generate-deal-ticket-query.ts +++ b/apps/trading-e2e/src/support/mocks/generate-deal-ticket-query.ts @@ -1,22 +1,70 @@ +import type { DealTicketQuery } from '@vegaprotocol/deal-ticket'; import { MarketState, MarketTradingMode } from '@vegaprotocol/types'; import merge from 'lodash/merge'; import type { PartialDeep } from 'type-fest'; -import type { DealTicketQuery } from '@vegaprotocol/deal-ticket'; export const generateDealTicketQuery = ( override?: PartialDeep ): DealTicketQuery => { const defaultResult: DealTicketQuery = { market: { + __typename: 'Market', id: 'market-0', name: 'ETHBTC Quarterly (30 Jun 2022)', decimalPlaces: 2, positionDecimalPlaces: 0, state: MarketState.Active, tradingMode: MarketTradingMode.Continuous, + fees: { + __typename: 'Fees', + factors: { + __typename: 'FeeFactors', + makerFee: '0.0002', + infrastructureFee: '0.0005', + liquidityFee: '0.01', + }, + }, + priceMonitoringSettings: { + __typename: 'PriceMonitoringSettings', + parameters: { + __typename: 'PriceMonitoringParameters', + triggers: [ + { + __typename: 'PriceMonitoringTrigger', + horizonSecs: 43200, + probability: 0.9999999, + auctionExtensionSecs: 600, + }, + ], + }, + updateFrequencySecs: 1, + }, + riskFactors: { + __typename: 'RiskFactor', + market: + '54b78c1b877e106842ae156332ccec740ad98d6bad43143ac6a029501dd7c6e0', + short: '0.008571790367285281', + long: '0.008508132993273576', + }, + data: { + __typename: 'MarketData', + market: { + __typename: 'Market', + id: '54b78c1b877e106842ae156332ccec740ad98d6bad43143ac6a029501dd7c6e0', + }, + markPrice: '5749', + indicativeVolume: '0', + bestBidVolume: '5', + bestOfferVolume: '1', + bestStaticBidVolume: '5', + bestStaticOfferVolume: '1', + }, tradableInstrument: { + __typename: 'TradableInstrument', instrument: { + __typename: 'Instrument', product: { + __typename: 'Future', quoteName: 'BTC', settlementAsset: { __typename: 'Asset', @@ -24,11 +72,19 @@ export const generateDealTicketQuery = ( symbol: 'tBTC', name: 'tBTC TEST', }, - __typename: 'Future', }, - __typename: 'Instrument', }, - __typename: 'TradableInstrument', + riskModel: { + __typename: 'LogNormalRiskModel', + tau: 0.0001140771161, + riskAversionParameter: 0.01, + params: { + __typename: 'LogNormalModelParams', + r: 0.016, + sigma: 0.3, + mu: 0, + }, + }, }, depth: { __typename: 'MarketDepth', @@ -37,7 +93,6 @@ export const generateDealTicketQuery = ( price: '100', }, }, - __typename: 'Market', }, }; diff --git a/apps/trading/pages/markets/trade-grid.tsx b/apps/trading/pages/markets/trade-grid.tsx index 56b20c5ae..3438b232a 100644 --- a/apps/trading/pages/markets/trade-grid.tsx +++ b/apps/trading/pages/markets/trade-grid.tsx @@ -12,9 +12,13 @@ import { t } from '@vegaprotocol/react-helpers'; import { AccountsContainer } from '@vegaprotocol/accounts'; import { DepthChartContainer } from '@vegaprotocol/market-depth'; import { CandlesChartContainer } from '@vegaprotocol/candles-chart'; -import { GridTab, GridTabs } from '../../components/grid-tabs'; import { SelectMarketDialog } from '@vegaprotocol/market-list'; -import { ArrowDown, PriceCellChange } from '@vegaprotocol/ui-toolkit'; +import { + ArrowDown, + GridTab, + GridTabs, + PriceCellChange, +} from '@vegaprotocol/ui-toolkit'; import type { CandleClose } from '@vegaprotocol/types'; const TradingViews = { diff --git a/apps/trading/pages/portfolio/index.page.tsx b/apps/trading/pages/portfolio/index.page.tsx index 002e0fbbf..be6198a7b 100644 --- a/apps/trading/pages/portfolio/index.page.tsx +++ b/apps/trading/pages/portfolio/index.page.tsx @@ -3,10 +3,9 @@ import { t } from '@vegaprotocol/react-helpers'; import { PositionsContainer } from '@vegaprotocol/positions'; import { OrderListContainer } from '@vegaprotocol/order-list'; import { AccountsContainer } from '@vegaprotocol/accounts'; -import { AnchorButton } from '@vegaprotocol/ui-toolkit'; +import { AnchorButton, GridTab, GridTabs } from '@vegaprotocol/ui-toolkit'; import { WithdrawalsContainer } from './withdrawals/withdrawals-container'; -import { GridTab, GridTabs } from '../../components/grid-tabs'; const Portfolio = () => { const tabClassName = 'p-[16px] pl-[316px]'; diff --git a/libs/deal-ticket/src/__generated__/DealTicketQuery.ts b/libs/deal-ticket/src/__generated__/DealTicketQuery.ts deleted file mode 100644 index 610d413c1..000000000 --- a/libs/deal-ticket/src/__generated__/DealTicketQuery.ts +++ /dev/null @@ -1,132 +0,0 @@ -/* tslint:disable */ -/* eslint-disable */ -// @generated -// This file was automatically generated and should not be edited. - -import { MarketState, MarketTradingMode } from "@vegaprotocol/types"; - -// ==================================================== -// GraphQL query operation: DealTicketQuery -// ==================================================== - -export interface DealTicketQuery_market_tradableInstrument_instrument_product_settlementAsset { - __typename: "Asset"; - /** - * The id of the asset - */ - id: string; - /** - * The symbol of the asset (e.g: GBP) - */ - symbol: string; - /** - * The full name of the asset (e.g: Great British Pound) - */ - name: string; -} - -export interface DealTicketQuery_market_tradableInstrument_instrument_product { - __typename: "Future"; - /** - * String representing the quote (e.g. BTCUSD -> USD is quote) - */ - quoteName: string; - /** - * The name of the asset (string) - */ - settlementAsset: DealTicketQuery_market_tradableInstrument_instrument_product_settlementAsset; -} - -export interface DealTicketQuery_market_tradableInstrument_instrument { - __typename: "Instrument"; - /** - * A reference to or instance of a fully specified product, including all required product parameters for that product (Product union) - */ - product: DealTicketQuery_market_tradableInstrument_instrument_product; -} - -export interface DealTicketQuery_market_tradableInstrument { - __typename: "TradableInstrument"; - /** - * An instance of or reference to a fully specified instrument. - */ - instrument: DealTicketQuery_market_tradableInstrument_instrument; -} - -export interface DealTicketQuery_market_depth_lastTrade { - __typename: "Trade"; - /** - * The price of the trade (probably initially the passive order price, other determination algorithms are possible though) (uint64) - */ - price: string; -} - -export interface DealTicketQuery_market_depth { - __typename: "MarketDepth"; - /** - * Last trade for the given market (if available) - */ - lastTrade: DealTicketQuery_market_depth_lastTrade | null; -} - -export interface DealTicketQuery_market { - __typename: "Market"; - /** - * Market ID - */ - id: string; - /** - * Market full name - */ - name: string; - /** - * decimalPlaces indicates the number of decimal places that an integer must be shifted by in order to get a correct - * number denominated in the currency of the Market. (uint64) - * - * Examples: - * Currency Balance decimalPlaces Real Balance - * GBP 100 0 GBP 100 - * GBP 100 2 GBP 1.00 - * GBP 100 4 GBP 0.01 - * GBP 1 4 GBP 0.0001 ( 0.01p ) - * - * GBX (pence) 100 0 GBP 1.00 (100p ) - * GBX (pence) 100 2 GBP 0.01 ( 1p ) - * GBX (pence) 100 4 GBP 0.0001 ( 0.01p ) - * GBX (pence) 1 4 GBP 0.000001 ( 0.0001p) - */ - decimalPlaces: number; - /** - * positionDecimalPlaces indicated the number of decimal places that an integer must be shifted in order to get a correct size (uint64). - * i.e. 0 means there are no fractional orders for the market, and order sizes are always whole sizes. - * 2 means sizes given as 10^2 * desired size, e.g. a desired size of 1.23 is represented as 123 in this market. - */ - positionDecimalPlaces: number; - /** - * Current state of the market - */ - state: MarketState; - /** - * Current mode of execution of the market - */ - tradingMode: MarketTradingMode; - /** - * An instance of or reference to a tradable instrument. - */ - tradableInstrument: DealTicketQuery_market_tradableInstrument; - /** - * Current depth on the order book for this market - */ - depth: DealTicketQuery_market_depth; -} - -export interface DealTicketQuery { - /** - * An instrument that is trading on the VEGA network - */ - market: DealTicketQuery_market | null; -} - -export interface DealTicketQueryVariables { - marketId: string; -} diff --git a/libs/deal-ticket/src/components/__generated__/DealTicketQuery.ts b/libs/deal-ticket/src/components/__generated__/DealTicketQuery.ts index 5bb0c3d36..11a36dd17 100644 --- a/libs/deal-ticket/src/components/__generated__/DealTicketQuery.ts +++ b/libs/deal-ticket/src/components/__generated__/DealTicketQuery.ts @@ -9,12 +9,150 @@ import { MarketState, MarketTradingMode } from "@vegaprotocol/types"; // GraphQL query operation: DealTicketQuery // ==================================================== +export interface DealTicketQuery_market_fees_factors { + __typename: "FeeFactors"; + /** + * The factor applied to calculate MakerFees, a non-negative float + */ + makerFee: string; + /** + * The factor applied to calculate InfrastructureFees, a non-negative float + */ + infrastructureFee: string; + /** + * The factor applied to calculate LiquidityFees, a non-negative float + */ + liquidityFee: string; +} + +export interface DealTicketQuery_market_fees { + __typename: "Fees"; + /** + * The factors used to calculate the different fees + */ + factors: DealTicketQuery_market_fees_factors; +} + +export interface DealTicketQuery_market_priceMonitoringSettings_parameters_triggers { + __typename: "PriceMonitoringTrigger"; + /** + * Price monitoring projection horizon τ in seconds (> 0). + */ + horizonSecs: number; + /** + * Price monitoring probability level p. (>0 and < 1) + */ + probability: number; + /** + * Price monitoring auction extension duration in seconds should the price + * breach it's theoretical level over the specified horizon at the specified + * probability level (> 0) + */ + auctionExtensionSecs: number; +} + +export interface DealTicketQuery_market_priceMonitoringSettings_parameters { + __typename: "PriceMonitoringParameters"; + /** + * The list of triggers for this price monitoring + */ + triggers: DealTicketQuery_market_priceMonitoringSettings_parameters_triggers[] | null; +} + +export interface DealTicketQuery_market_priceMonitoringSettings { + __typename: "PriceMonitoringSettings"; + /** + * Specified a set of PriceMonitoringParameters to be use for price monitoring purposes + */ + parameters: DealTicketQuery_market_priceMonitoringSettings_parameters | null; + /** + * How often (in seconds) the price monitoring bounds should be updated + */ + updateFrequencySecs: number; +} + +export interface DealTicketQuery_market_riskFactors { + __typename: "RiskFactor"; + /** + * market the risk factor was emitted for + */ + market: string; + /** + * short factor + */ + short: string; + /** + * long factor + */ + long: string; +} + +export interface DealTicketQuery_market_data_market { + __typename: "Market"; + /** + * Market ID + */ + id: string; +} + +export interface DealTicketQuery_market_data { + __typename: "MarketData"; + /** + * market id of the associated mark price + */ + market: DealTicketQuery_market_data_market; + /** + * the mark price (actually an unsigned int) + */ + markPrice: string; + /** + * indicative volume if the auction ended now, 0 if not in auction mode + */ + indicativeVolume: string; + /** + * the aggregated volume being bid at the best bid price. + */ + bestBidVolume: string; + /** + * the aggregated volume being offered at the best offer price. + */ + bestOfferVolume: string; + /** + * the aggregated volume being offered at the best static bid price, excluding pegged orders + */ + bestStaticBidVolume: string; + /** + * the aggregated volume being offered at the best static offer price, excluding pegged orders. + */ + bestStaticOfferVolume: string; +} + +export interface DealTicketQuery_market_tradableInstrument_instrument_product_settlementAsset { + __typename: "Asset"; + /** + * The id of the asset + */ + id: string; + /** + * The symbol of the asset (e.g: GBP) + */ + symbol: string; + /** + * The full name of the asset (e.g: Great British Pound) + */ + name: string; +} + export interface DealTicketQuery_market_tradableInstrument_instrument_product { __typename: "Future"; /** * String representing the quote (e.g. BTCUSD -> USD is quote) */ quoteName: string; + /** + * The name of the asset (string) + */ + settlementAsset: DealTicketQuery_market_tradableInstrument_instrument_product_settlementAsset; } export interface DealTicketQuery_market_tradableInstrument_instrument { @@ -25,12 +163,70 @@ export interface DealTicketQuery_market_tradableInstrument_instrument { product: DealTicketQuery_market_tradableInstrument_instrument_product; } +export interface DealTicketQuery_market_tradableInstrument_riskModel_LogNormalRiskModel_params { + __typename: "LogNormalModelParams"; + /** + * r parameter + */ + r: number; + /** + * sigma parameter + */ + sigma: number; + /** + * mu parameter + */ + mu: number; +} + +export interface DealTicketQuery_market_tradableInstrument_riskModel_LogNormalRiskModel { + __typename: "LogNormalRiskModel"; + /** + * Tau parameter of the risk model + */ + tau: number; + /** + * Lambda parameter of the risk model + */ + riskAversionParameter: number; + /** + * Params for the log normal risk model + */ + params: DealTicketQuery_market_tradableInstrument_riskModel_LogNormalRiskModel_params; +} + +export interface DealTicketQuery_market_tradableInstrument_riskModel_SimpleRiskModel_params { + __typename: "SimpleRiskModelParams"; + /** + * Risk factor for long + */ + factorLong: number; + /** + * Risk factor for short + */ + factorShort: number; +} + +export interface DealTicketQuery_market_tradableInstrument_riskModel_SimpleRiskModel { + __typename: "SimpleRiskModel"; + /** + * Params for the simple risk model + */ + params: DealTicketQuery_market_tradableInstrument_riskModel_SimpleRiskModel_params; +} + +export type DealTicketQuery_market_tradableInstrument_riskModel = DealTicketQuery_market_tradableInstrument_riskModel_LogNormalRiskModel | DealTicketQuery_market_tradableInstrument_riskModel_SimpleRiskModel; + export interface DealTicketQuery_market_tradableInstrument { __typename: "TradableInstrument"; /** * An instance of or reference to a fully specified instrument. */ instrument: DealTicketQuery_market_tradableInstrument_instrument; + /** + * A reference to a risk model that is valid for the instrument + */ + riskModel: DealTicketQuery_market_tradableInstrument_riskModel; } export interface DealTicketQuery_market_depth_lastTrade { @@ -90,6 +286,22 @@ export interface DealTicketQuery_market { * Current mode of execution of the market */ tradingMode: MarketTradingMode; + /** + * Fees related data + */ + fees: DealTicketQuery_market_fees; + /** + * Price monitoring settings for the market + */ + priceMonitoringSettings: DealTicketQuery_market_priceMonitoringSettings; + /** + * risk factors for the market + */ + riskFactors: DealTicketQuery_market_riskFactors | null; + /** + * marketData for the given market + */ + data: DealTicketQuery_market_data | null; /** * An instance of or reference to a tradable instrument. */ diff --git a/libs/deal-ticket/src/__generated__/OrderEvent.ts b/libs/deal-ticket/src/components/__generated__/OrderEvent.ts similarity index 100% rename from libs/deal-ticket/src/__generated__/OrderEvent.ts rename to libs/deal-ticket/src/components/__generated__/OrderEvent.ts diff --git a/libs/deal-ticket/src/components/__generated__/index.ts b/libs/deal-ticket/src/components/__generated__/index.ts new file mode 100644 index 000000000..f34fa3e9e --- /dev/null +++ b/libs/deal-ticket/src/components/__generated__/index.ts @@ -0,0 +1,2 @@ +export * from './DealTicketQuery'; +export * from './OrderEvent'; diff --git a/libs/deal-ticket/src/components/deal-ticket-container.tsx b/libs/deal-ticket/src/components/deal-ticket-container.tsx index b7c09ff1b..85f67446e 100644 --- a/libs/deal-ticket/src/components/deal-ticket-container.tsx +++ b/libs/deal-ticket/src/components/deal-ticket-container.tsx @@ -1,11 +1,14 @@ import { gql, useQuery } from '@apollo/client'; -import { AsyncRenderer, Splash } from '@vegaprotocol/ui-toolkit'; +import { + AsyncRenderer, + GridTab, + GridTabs, + Splash, +} from '@vegaprotocol/ui-toolkit'; import { DealTicketManager } from './deal-ticket-manager'; -import type { - DealTicketQuery, - DealTicketQuery_market, -} from '../__generated__/DealTicketQuery'; import { t } from '@vegaprotocol/react-helpers'; +import { Info } from './info-market'; +import type { DealTicketQuery_market, DealTicketQuery } from './__generated__'; const DEAL_TICKET_QUERY = gql` query DealTicketQuery($marketId: ID!) { @@ -16,6 +19,40 @@ const DEAL_TICKET_QUERY = gql` positionDecimalPlaces state tradingMode + fees { + factors { + makerFee + infrastructureFee + liquidityFee + } + } + priceMonitoringSettings { + parameters { + triggers { + horizonSecs + probability + auctionExtensionSecs + } + } + updateFrequencySecs + } + riskFactors { + market + short + long + } + data { + market { + id + } + markPrice + indicativeVolume + bestBidVolume + bestOfferVolume + bestStaticBidVolume + bestStaticOfferVolume + indicativeVolume + } tradableInstrument { instrument { product { @@ -29,6 +66,23 @@ const DEAL_TICKET_QUERY = gql` } } } + riskModel { + ... on LogNormalRiskModel { + tau + riskAversionParameter + params { + r + sigma + mu + } + } + ... on SimpleRiskModel { + params { + factorLong + factorShort + } + } + } } depth { lastTrade { @@ -57,18 +111,45 @@ export const DealTicketContainer = ({ }); return ( - data={data} loading={loading} error={error}> - {data && data.market ? ( - children ? ( - children(data) - ) : ( - - ) - ) : ( - -

{t('Could not load market')}

-
- )} - + + + + data={data} + loading={loading} + error={error} + > + {data && data.market ? ( + children ? ( + children(data) + ) : ( + + ) + ) : ( + +

{t('Could not load market')}

+
+ )} + +
+ + + data={data} + loading={loading} + error={error} + > + {data && data.market ? ( + children ? ( + children(data) + ) : ( + + ) + ) : ( + +

{t('Could not load market')}

+
+ )} + +
+
); }; diff --git a/libs/deal-ticket/src/components/deal-ticket-manager.tsx b/libs/deal-ticket/src/components/deal-ticket-manager.tsx index 7a4bdc8bd..bf3090a2d 100644 --- a/libs/deal-ticket/src/components/deal-ticket-manager.tsx +++ b/libs/deal-ticket/src/components/deal-ticket-manager.tsx @@ -6,7 +6,7 @@ import { VegaTxStatus } from '@vegaprotocol/wallet'; import { DealTicket } from './deal-ticket'; import { OrderDialog } from './order-dialog'; import { useOrderSubmit } from '../hooks/use-order-submit'; -import type { DealTicketQuery_market } from '../__generated__/DealTicketQuery'; +import type { DealTicketQuery_market } from './__generated__/DealTicketQuery'; export interface DealTicketManagerProps { market: DealTicketQuery_market; diff --git a/libs/deal-ticket/src/components/deal-ticket.tsx b/libs/deal-ticket/src/components/deal-ticket.tsx index df5d2f4c7..4a98bcd68 100644 --- a/libs/deal-ticket/src/components/deal-ticket.tsx +++ b/libs/deal-ticket/src/components/deal-ticket.tsx @@ -7,11 +7,11 @@ import { TypeSelector } from './type-selector'; import { SideSelector } from './side-selector'; import { DealTicketAmount } from './deal-ticket-amount'; import { TimeInForceSelector } from './time-in-force-selector'; -import { ExpirySelector } from './expiry-selector'; -import type { DealTicketQuery_market } from '../__generated__/DealTicketQuery'; +import { useOrderValidation } from '../hooks/use-order-validation'; +import type { DealTicketQuery_market } from './__generated__/DealTicketQuery'; import type { Order } from '../utils/get-default-order'; import { getDefaultOrder } from '../utils/get-default-order'; -import { useOrderValidation } from '../hooks/use-order-validation'; +import { ExpirySelector } from './expiry-selector'; export type TransactionStatus = 'default' | 'pending'; diff --git a/libs/deal-ticket/src/components/index.ts b/libs/deal-ticket/src/components/index.ts new file mode 100644 index 000000000..beb86e0d7 --- /dev/null +++ b/libs/deal-ticket/src/components/index.ts @@ -0,0 +1,13 @@ +export * from './__generated__'; +export * from './deal-ticket-amount'; +export * from './deal-ticket-container'; +export * from './deal-ticket-limit-amount'; +export * from './deal-ticket-manager'; +export * from './deal-ticket-market-amount'; +export * from './deal-ticket'; +export * from './expiry-selector'; +export * from './info-market'; +export * from './order-dialog'; +export * from './side-selector'; +export * from './time-in-force-selector'; +export * from './type-selector'; diff --git a/libs/deal-ticket/src/components/info-market.tsx b/libs/deal-ticket/src/components/info-market.tsx new file mode 100644 index 000000000..9eb0e9e18 --- /dev/null +++ b/libs/deal-ticket/src/components/info-market.tsx @@ -0,0 +1,193 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { + addDecimalsFormatNumber, + formatNumber, + formatNumberPercentage, + t, +} from '@vegaprotocol/react-helpers'; +import { + KeyValueTable, + KeyValueTableRow, + AccordionPanel, +} from '@vegaprotocol/ui-toolkit'; +import startCase from 'lodash/startCase'; +import pick from 'lodash/pick'; +import omit from 'lodash/omit'; +import type { DealTicketQuery_market } from './__generated__/DealTicketQuery'; +import BigNumber from 'bignumber.js'; + +export interface InfoProps { + market: DealTicketQuery_market; +} + +export const Info = ({ market }: InfoProps) => { + const headerClassName = + 'text-h5 font-bold uppercase text-black dark:text-white'; + return ( +
+
+

{t('Market data')}

+ + +

+ {t( + 'All fees are paid by price takers and are a % of the trade notional value. Fees are not paid during auction uncrossing.' + )} +

+ + } + /> + + } + /> +
+ +
+

{t('Market specification')}

+ + } + /> + + } + /> + + } + /> + + } + /> + {(market.priceMonitoringSettings?.parameters?.triggers ?? []).map( + (trigger, i) => ( + } + /> + ) + )} +
+
+ ); +}; + +interface RowProps { + field: string; + value: any; + decimalPlaces?: number; + asPercentage?: boolean; + unformatted?: boolean; +} + +const Row = ({ + field, + value, + decimalPlaces, + asPercentage, + unformatted, +}: RowProps) => { + const isNumber = typeof value === 'number' || !isNaN(Number(value)); + const isPrimitive = typeof value === 'string' || isNumber; + const className = 'text-black dark:text-white text-ui !px-0 !font-normal'; + if (isPrimitive) { + return ( + + {startCase(t(field))} + {isNumber && !unformatted + ? decimalPlaces + ? addDecimalsFormatNumber(value, decimalPlaces) + : asPercentage + ? formatNumberPercentage(new BigNumber(value)) + : formatNumber(Number(value)) + : value} + + ); + } + return null; +}; + +export interface MarketInfoTableProps { + data: any; + decimalPlaces?: number; + asPercentage?: boolean; + unformatted?: boolean; + omits?: string[]; +} + +export const MarketInfoTable = ({ + data, + decimalPlaces, + asPercentage, + unformatted, + omits = ['id', '__typename'], +}: MarketInfoTableProps) => { + return ( + + {Object.entries(omit(data, ...omits) || []).map(([key, value]) => ( + + ))} + + ); +}; diff --git a/libs/deal-ticket/src/components/order-dialog.tsx b/libs/deal-ticket/src/components/order-dialog.tsx index 17498ec8f..d3bbe4926 100644 --- a/libs/deal-ticket/src/components/order-dialog.tsx +++ b/libs/deal-ticket/src/components/order-dialog.tsx @@ -1,6 +1,6 @@ import { Icon, Loader } from '@vegaprotocol/ui-toolkit'; import type { ReactNode } from 'react'; -import type { OrderEvent_busEvents_event_Order } from '../__generated__/OrderEvent'; +import type { OrderEvent_busEvents_event_Order } from './__generated__/OrderEvent'; import { addDecimalsFormatNumber, t } from '@vegaprotocol/react-helpers'; import type { VegaTxState } from '@vegaprotocol/wallet'; import { VegaTxStatus } from '@vegaprotocol/wallet'; diff --git a/libs/deal-ticket/src/hooks/use-order-submit.ts b/libs/deal-ticket/src/hooks/use-order-submit.ts index 53213e067..75c923c30 100644 --- a/libs/deal-ticket/src/hooks/use-order-submit.ts +++ b/libs/deal-ticket/src/hooks/use-order-submit.ts @@ -8,8 +8,8 @@ import type { OrderEvent, OrderEventVariables, OrderEvent_busEvents_event_Order, -} from '../__generated__/OrderEvent'; -import type { DealTicketQuery_market } from '../__generated__/DealTicketQuery'; +} from '../components/__generated__/OrderEvent'; +import type { DealTicketQuery_market } from '../components/__generated__/DealTicketQuery'; const ORDER_EVENT_SUB = gql` subscription OrderEvent($partyId: ID!) { diff --git a/libs/deal-ticket/src/hooks/use-order-validation.tsx b/libs/deal-ticket/src/hooks/use-order-validation.tsx index 0f4c9ba67..c73668940 100644 --- a/libs/deal-ticket/src/hooks/use-order-validation.tsx +++ b/libs/deal-ticket/src/hooks/use-order-validation.tsx @@ -8,8 +8,8 @@ import { } from '@vegaprotocol/wallet'; import { MarketState, MarketTradingMode } from '@vegaprotocol/types'; import type { Order } from '../utils/get-default-order'; -import type { DealTicketQuery_market } from '../__generated__/DealTicketQuery'; import { ERROR_SIZE_DECIMAL } from '../utils/validate-size'; +import type { DealTicketQuery_market } from '../components/__generated__/DealTicketQuery'; export type ValidationProps = { step: number; diff --git a/libs/deal-ticket/src/index.ts b/libs/deal-ticket/src/index.ts index 98f76deb4..ef14c944d 100644 --- a/libs/deal-ticket/src/index.ts +++ b/libs/deal-ticket/src/index.ts @@ -1,16 +1,4 @@ -export * from './components/expiry-selector'; -export * from './components/type-selector'; -export * from './components/time-in-force-selector'; -export * from './components/side-selector'; -export * from './components/deal-ticket'; -export * from './components/deal-ticket-amount'; -export * from './components/deal-ticket-limit-amount'; -export * from './components/deal-ticket-market-amount'; -export * from './components/deal-ticket-manager'; -export * from './components/order-dialog'; -export * from './components/deal-ticket-container'; -export * from './__generated__/DealTicketQuery'; -export * from './__generated__/OrderEvent'; +export * from './components'; export * from './utils/get-default-order'; export * from './hooks/use-order-submit'; export * from './hooks/use-order-validation'; diff --git a/libs/deal-ticket/src/utils/get-default-order.ts b/libs/deal-ticket/src/utils/get-default-order.ts index 7e011a0b2..dd7519153 100644 --- a/libs/deal-ticket/src/utils/get-default-order.ts +++ b/libs/deal-ticket/src/utils/get-default-order.ts @@ -1,6 +1,6 @@ import { OrderTimeInForce, OrderType, OrderSide } from '@vegaprotocol/wallet'; -import type { DealTicketQuery_market } from '../__generated__/DealTicketQuery'; import { toDecimal } from '@vegaprotocol/react-helpers'; +import type { DealTicketQuery_market } from '../components/__generated__/DealTicketQuery'; export type Order = | { diff --git a/libs/ui-toolkit/src/components/accordion/accordion.spec.tsx b/libs/ui-toolkit/src/components/accordion/accordion.spec.tsx new file mode 100644 index 000000000..9412dcb6f --- /dev/null +++ b/libs/ui-toolkit/src/components/accordion/accordion.spec.tsx @@ -0,0 +1,33 @@ +import { fireEvent, render, screen } from '@testing-library/react'; + +import { AccordionPanel } from './accordion'; + +describe('Accordion', () => { + it('should render successfully', () => { + render( + + ); + expect(screen.queryByTestId('accordion-title')).toHaveTextContent( + 'Lorem ipsum title' + ); + }); + + it('should toggle and open expansion panel', () => { + render( + + ); + fireEvent.click(screen.getByTestId('accordion-toggle')); + expect(screen.queryByTestId('accordion-title')).toHaveTextContent( + 'Lorem ipsum title' + ); + expect(screen.getByTestId('accordion-content')).toHaveTextContent( + 'Lorem ipsum content' + ); + }); +}); diff --git a/libs/ui-toolkit/src/components/accordion/accordion.stories.tsx b/libs/ui-toolkit/src/components/accordion/accordion.stories.tsx new file mode 100644 index 000000000..e0ebd96d7 --- /dev/null +++ b/libs/ui-toolkit/src/components/accordion/accordion.stories.tsx @@ -0,0 +1,17 @@ +import type { Story, Meta } from '@storybook/react'; +import { AccordionPanel } from './accordion'; + +export default { + component: AccordionPanel, + title: 'Accordion', +} as Meta; + +const Template: Story = (args) => ( + +); + +export const Default = Template.bind({}); +Default.args = { + title: 'Title of expansion panel', + content: 'Lorem ipsum', +}; diff --git a/libs/ui-toolkit/src/components/accordion/accordion.tsx b/libs/ui-toolkit/src/components/accordion/accordion.tsx new file mode 100644 index 000000000..58eeafb9c --- /dev/null +++ b/libs/ui-toolkit/src/components/accordion/accordion.tsx @@ -0,0 +1,73 @@ +import React, { useRef, useState } from 'react'; + +export interface AccordionProps { + title: React.ReactNode; + content: React.ReactNode; +} + +export const AccordionPanel = ({ title, content }: AccordionProps) => { + const [active, setActive] = useState(false); + const [height, setHeight] = useState('0px'); + const [rotate, setRotate] = useState( + 'transform duration-300 ease rotate-180' + ); + + const contentSpace = useRef(null); + + const toggleAccordion = () => { + setActive((prevState) => !prevState); + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + setHeight(active ? '0px' : `${contentSpace.current.scrollHeight}px`); + setRotate( + active + ? 'transform duration-300 ease rotate-180' + : 'transform duration-300 ease' + ); + }; + + return ( +
+ +
+
+ {content} +
+
+
+ ); +}; diff --git a/libs/ui-toolkit/src/components/accordion/index.ts b/libs/ui-toolkit/src/components/accordion/index.ts new file mode 100644 index 000000000..ce956fe2e --- /dev/null +++ b/libs/ui-toolkit/src/components/accordion/index.ts @@ -0,0 +1 @@ +export * from './accordion'; diff --git a/apps/trading/components/grid-tabs/grid-tabs.tsx b/libs/ui-toolkit/src/components/grid-tabs/grid-tabs.tsx similarity index 100% rename from apps/trading/components/grid-tabs/grid-tabs.tsx rename to libs/ui-toolkit/src/components/grid-tabs/grid-tabs.tsx diff --git a/apps/trading/components/grid-tabs/index.ts b/libs/ui-toolkit/src/components/grid-tabs/index.ts similarity index 100% rename from apps/trading/components/grid-tabs/index.ts rename to libs/ui-toolkit/src/components/grid-tabs/index.ts diff --git a/libs/ui-toolkit/src/components/index.ts b/libs/ui-toolkit/src/components/index.ts index 01ce9b509..340df0021 100644 --- a/libs/ui-toolkit/src/components/index.ts +++ b/libs/ui-toolkit/src/components/index.ts @@ -1,3 +1,4 @@ +export * from './accordion'; export * from './ag-grid'; export * from './arrows'; export * from './async-renderer'; @@ -7,13 +8,14 @@ export * from './card'; export * from './copy-with-tooltip'; export * from './dialog'; export * from './dropdown-menu'; -export * from './link'; export * from './form-group'; +export * from './grid-tabs'; export * from './icon'; export * from './indicator'; export * from './input'; export * from './input-error'; export * from './key-value-table'; +export * from './link'; export * from './loader'; export * from './lozenge'; export * from './price-change'; diff --git a/libs/ui-toolkit/src/components/key-value-table/key-value-table.tsx b/libs/ui-toolkit/src/components/key-value-table/key-value-table.tsx index 7df96b14f..ae71f9ad7 100644 --- a/libs/ui-toolkit/src/components/key-value-table/key-value-table.tsx +++ b/libs/ui-toolkit/src/components/key-value-table/key-value-table.tsx @@ -63,6 +63,9 @@ export interface KeyValueTableRowProps numerical?: boolean; // makes all values monospace muted?: boolean; inline?: boolean; + noBorder?: boolean; + dtClassName?: string; + ddClassName?: string; } export const KeyValueTableRow = ({ @@ -71,9 +74,13 @@ export const KeyValueTableRow = ({ muted, numerical, inline = true, + noBorder = false, + dtClassName, + ddClassName, }: KeyValueTableRowProps) => { const dlClassName = classNames( - 'flex gap-1 flex-wrap justify-between border-b first:border-t border-black dark:border-white', + 'flex gap-1 flex-wrap justify-between ', + { 'border-b first:border-t border-black dark:border-white': !noBorder }, { 'flex-col items-start': !inline }, { 'flex-row items-center': inline }, { @@ -82,18 +89,19 @@ export const KeyValueTableRow = ({ }, className ); - const dtClassName = `break-words font-medium uppercase align-top p-4 capitalize`; - const ddClassName = classNames( + const dtClassNames = `break-words font-medium uppercase align-top p-4 capitalize ${dtClassName}`; + const ddClassNames = classNames( 'align-top p-4 text-black/60 dark:text-white/60 break-words', { 'font-mono': numerical, - } + }, + ddClassName ); return (
-
{children[0]}
-
{children[1]}
+
{children[0]}
+
{children[1]}
); };