From e674efdb14385570c62a1edc9577f2d301e07625 Mon Sep 17 00:00:00 2001
From: Art
Date: Mon, 5 Sep 2022 14:06:58 +0200
Subject: [PATCH] Feat/707 link to market proposal (#1222)
* feat: link to market proposal (707)
* feat: link to market proposal (707)
* removed a line
* removed label which made edd and barney sad
---
.../proposals-list/proposals-list.tsx | 10 +--
.../mocks/generate-market-info-query.ts | 9 ++
apps/trading/.env | 3 +-
apps/trading/.env.devnet | 1 +
apps/trading/.env.mainnet | 1 +
apps/trading/.env.stagnet3 | 1 +
apps/trading/.env.testnet | 1 +
.../__generated__/MarketInfoQuery.ts | 32 +++++++
.../src/components/info-market-query.ts | 21 ++---
.../src/components/info-market.tsx | 42 ++++++++-
.../src/utils/compile-environment.ts | 2 +
.../src/utils/validate-environment.ts | 1 +
libs/ui-toolkit/src/components/icon/icon.tsx | 4 +-
libs/ui-toolkit/src/components/link/index.ts | 2 +-
.../src/components/link/link.spec.tsx | 86 ++++++++++++-------
libs/ui-toolkit/src/components/link/link.tsx | 26 +++++-
16 files changed, 186 insertions(+), 56 deletions(-)
diff --git a/apps/token/src/routes/governance/components/proposals-list/proposals-list.tsx b/apps/token/src/routes/governance/components/proposals-list/proposals-list.tsx
index ab99ec9d4..63d5c05c2 100644
--- a/apps/token/src/routes/governance/components/proposals-list/proposals-list.tsx
+++ b/apps/token/src/routes/governance/components/proposals-list/proposals-list.tsx
@@ -9,6 +9,7 @@ import Routes from '../../../routes';
import { Button } from '@vegaprotocol/ui-toolkit';
import { Link } from 'react-router-dom';
import { Links } from '../../../../config';
+import { ExternalLink } from '@vegaprotocol/ui-toolkit';
interface ProposalsListProps {
proposals: Proposals_proposals[];
@@ -65,14 +66,9 @@ export const ProposalsList = ({ proposals }: ProposalsListProps) => {
{t(
`The Vega network is governed by the community. View active proposals, vote on them or propose changes to the network.`
)}{' '}
-
+
{t(`Find out more about Vega governance`)}
-
+
{proposals.length > 0 && (
diff --git a/apps/trading-e2e/src/support/mocks/generate-market-info-query.ts b/apps/trading-e2e/src/support/mocks/generate-market-info-query.ts
index 926fc4120..39238e0b0 100644
--- a/apps/trading-e2e/src/support/mocks/generate-market-info-query.ts
+++ b/apps/trading-e2e/src/support/mocks/generate-market-info-query.ts
@@ -20,6 +20,15 @@ export const generateMarketInfoQuery = (
positionDecimalPlaces: 0,
state: MarketState.STATE_ACTIVE,
tradingMode: MarketTradingMode.TRADING_MODE_CONTINUOUS,
+ proposal: {
+ __typename: 'Proposal',
+ id: 'market-0',
+ rationale: {
+ __typename: 'ProposalRationale',
+ title: 'ETHBTC',
+ description: '',
+ },
+ },
accounts: [
{
type: AccountType.ACCOUNT_TYPE_INSURANCE,
diff --git a/apps/trading/.env b/apps/trading/.env
index 005b9b8e6..5e9905ad6 100644
--- a/apps/trading/.env
+++ b/apps/trading/.env
@@ -6,4 +6,5 @@ NX_ETHERSCAN_URL=https://ropsten.etherscan.io
NX_VEGA_NETWORKS={\"MAINNET\":\"https://alpha.console.vega.xyz\"}
NX_USE_ENV_OVERRIDES=1
NX_VEGA_EXPLORER_URL=https://explorer.fairground.wtf
-NX_VEGA_WALLET_URL=http://localhost:1789/api/v1
+NX_VEGA_TOKEN_URL=https://token.fairground.wtf
+NX_VEGA_WALLET_URL=http://localhost:1789/api/v1
\ No newline at end of file
diff --git a/apps/trading/.env.devnet b/apps/trading/.env.devnet
index de04803c7..b8d601848 100644
--- a/apps/trading/.env.devnet
+++ b/apps/trading/.env.devnet
@@ -6,3 +6,4 @@ NX_VEGA_NETWORKS={\"MAINNET\":\"https://alpha.console.vega.xyz\"}
NX_ETHEREUM_PROVIDER_URL=https://ropsten.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
NX_ETHERSCAN_URL=https://ropsten.etherscan.io
NX_VEGA_EXPLORER_URL=https://dev.explorer.vega.xyz
+NX_VEGA_TOKEN_URL=https://token.fairground.wtf
\ No newline at end of file
diff --git a/apps/trading/.env.mainnet b/apps/trading/.env.mainnet
index 9aa4b5d17..c23385bad 100644
--- a/apps/trading/.env.mainnet
+++ b/apps/trading/.env.mainnet
@@ -6,3 +6,4 @@ NX_VEGA_NETWORKS='{\"MAINNET\":\"https://alpha.console.vega.xyz\"}'
NX_ETHEREUM_PROVIDER_URL=https://mainnet.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
NX_ETHERSCAN_URL=https://etherscan.io
NX_VEGA_EXPLORER_URL=https://explorer.vega.xyz
+NX_VEGA_TOKEN_URL=https://token.vega.xyz
\ No newline at end of file
diff --git a/apps/trading/.env.stagnet3 b/apps/trading/.env.stagnet3
index c2d7fe4de..353c8bfd9 100644
--- a/apps/trading/.env.stagnet3
+++ b/apps/trading/.env.stagnet3
@@ -6,3 +6,4 @@ NX_VEGA_NETWORKS='{\"MAINNET\":\"https://alpha.console.vega.xyz\"}'
NX_ETHEREUM_PROVIDER_URL=https://ropsten.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
NX_ETHERSCAN_URL=https://ropsten.etherscan.io
NX_VEGA_EXPLORER_URL=https://staging3.explorer.vega.xyz
+NX_VEGA_TOKEN_URL=https://token.fairground.wtf
\ No newline at end of file
diff --git a/apps/trading/.env.testnet b/apps/trading/.env.testnet
index 502a98025..5bd96ac0e 100644
--- a/apps/trading/.env.testnet
+++ b/apps/trading/.env.testnet
@@ -5,3 +5,4 @@ NX_VEGA_NETWORKS='{\"MAINNET\":\"https://alpha.console.vega.xyz\"}'
NX_ETHEREUM_PROVIDER_URL=https://ropsten.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
NX_ETHERSCAN_URL=https://ropsten.etherscan.io
NX_VEGA_EXPLORER_URL=https://explorer.fairground.wtf
+NX_VEGA_TOKEN_URL=https://token.fairground.wtf
\ No newline at end of file
diff --git a/libs/deal-ticket/src/components/__generated__/MarketInfoQuery.ts b/libs/deal-ticket/src/components/__generated__/MarketInfoQuery.ts
index 010e84997..0193664e7 100644
--- a/libs/deal-ticket/src/components/__generated__/MarketInfoQuery.ts
+++ b/libs/deal-ticket/src/components/__generated__/MarketInfoQuery.ts
@@ -9,6 +9,34 @@ import { Interval, MarketState, AccountType, MarketTradingMode, AuctionTrigger }
// GraphQL query operation: MarketInfoQuery
// ====================================================
+export interface MarketInfoQuery_market_proposal_rationale {
+ __typename: "ProposalRationale";
+ /**
+ * Title to be used to give a short description of the proposal in lists.
+ * This is to be between 0 and 100 unicode characters.
+ * This is mandatory for all proposals.
+ */
+ title: string;
+ /**
+ * Description to show a short title / something in case the link goes offline.
+ * This is to be between 0 and 20k unicode characters.
+ * This is mandatory for all proposals.
+ */
+ description: string;
+}
+
+export interface MarketInfoQuery_market_proposal {
+ __typename: "Proposal";
+ /**
+ * Proposal ID that is filled by Vega once proposal reaches the network
+ */
+ id: string | null;
+ /**
+ * Rationale behind the proposal
+ */
+ rationale: MarketInfoQuery_market_proposal_rationale;
+}
+
export interface MarketInfoQuery_market_accounts_asset {
__typename: "Asset";
/**
@@ -451,6 +479,10 @@ export interface MarketInfoQuery_market {
* Current state of the market
*/
state: MarketState;
+ /**
+ * The proposal that initiated this market
+ */
+ proposal: MarketInfoQuery_market_proposal | null;
/**
* Get account for a party or market
*/
diff --git a/libs/deal-ticket/src/components/info-market-query.ts b/libs/deal-ticket/src/components/info-market-query.ts
index 9ec53cf21..6c197b93a 100644
--- a/libs/deal-ticket/src/components/info-market-query.ts
+++ b/libs/deal-ticket/src/components/info-market-query.ts
@@ -8,6 +8,13 @@ export const MARKET_INFO_QUERY = gql`
decimalPlaces
positionDecimalPlaces
state
+ proposal {
+ id
+ rationale {
+ title
+ description
+ }
+ }
accounts {
type
asset {
@@ -16,13 +23,6 @@ export const MARKET_INFO_QUERY = gql`
balance
}
tradingMode
- accounts {
- type
- asset {
- id
- }
- balance
- }
fees {
factors {
makerFee
@@ -44,13 +44,6 @@ export const MARKET_INFO_QUERY = gql`
short
long
}
- accounts {
- type
- asset {
- id
- }
- balance
- }
data {
market {
id
diff --git a/libs/deal-ticket/src/components/info-market.tsx b/libs/deal-ticket/src/components/info-market.tsx
index 685c9272b..e7fb234e6 100644
--- a/libs/deal-ticket/src/components/info-market.tsx
+++ b/libs/deal-ticket/src/components/info-market.tsx
@@ -26,6 +26,14 @@ import { useQuery } from '@apollo/client';
import { totalFees } from '@vegaprotocol/market-list';
import { AccountType, Interval } from '@vegaprotocol/types';
import { MARKET_INFO_QUERY } from './info-market-query';
+import { ExternalLink } from '@vegaprotocol/ui-toolkit';
+
+import { generatePath } from 'react-router-dom';
+import { useEnvironment } from '@vegaprotocol/environment';
+
+const Links = {
+ PROPOSAL_PAGE: ':tokenUrl/governance/:proposalId',
+};
export interface InfoProps {
market: MarketInfoQuery_market;
@@ -68,7 +76,8 @@ export const MarketInfoContainer = ({ marketId }: MarketInfoContainerProps) => {
};
export const Info = ({ market }: InfoProps) => {
- const headerClassName = 'uppercase text-lg mb-4';
+ const { VEGA_TOKEN_URL } = useEnvironment();
+ const headerClassName = 'uppercase text-lg';
const dayVolume = calcCandleVolume(market);
const marketDataPanels = [
{
@@ -272,16 +281,45 @@ export const Info = ({ market }: InfoProps) => {
},
];
+ const marketGovPanels = [
+ {
+ title: t('Proposal'),
+ content: (
+
-
+
{t('Market specification')}
+ {VEGA_TOKEN_URL && market.proposal?.id && (
+
+
{t('Market governance')}
+
+
+ )}
);
};
diff --git a/libs/environment/src/utils/compile-environment.ts b/libs/environment/src/utils/compile-environment.ts
index 3b4de999a..1b61c3564 100644
--- a/libs/environment/src/utils/compile-environment.ts
+++ b/libs/environment/src/utils/compile-environment.ts
@@ -70,6 +70,8 @@ const getBundledEnvironmentValue = (key: EnvKey) => {
return process.env['NX_VEGA_EXPLORER_URL'];
case 'VEGA_WALLET_URL':
return process.env['NX_VEGA_WALLET_URL'];
+ case 'VEGA_TOKEN_URL':
+ return process.env['NX_VEGA_TOKEN_URL'];
}
};
diff --git a/libs/environment/src/utils/validate-environment.ts b/libs/environment/src/utils/validate-environment.ts
index 1488da896..260e8b275 100644
--- a/libs/environment/src/utils/validate-environment.ts
+++ b/libs/environment/src/utils/validate-environment.ts
@@ -21,6 +21,7 @@ const schemaObject = {
GITHUB_FEEDBACK_URL: z.optional(z.string()),
VEGA_ENV: z.nativeEnum(Networks),
VEGA_EXPLORER_URL: z.optional(z.string()),
+ VEGA_TOKEN_URL: z.optional(z.string()),
VEGA_NETWORKS: z
.object(
Object.keys(Networks).reduce(
diff --git a/libs/ui-toolkit/src/components/icon/icon.tsx b/libs/ui-toolkit/src/components/icon/icon.tsx
index 202bea14a..d9ea92b16 100644
--- a/libs/ui-toolkit/src/components/icon/icon.tsx
+++ b/libs/ui-toolkit/src/components/icon/icon.tsx
@@ -7,7 +7,7 @@ export type { IconName } from '@blueprintjs/icons';
export interface IconProps {
name: IconName;
className?: string;
- size?: 4 | 6 | 8 | 10 | 12 | 14 | 16;
+ size?: 2 | 3 | 4 | 6 | 8 | 10 | 12 | 14 | 16;
ariaLabel?: string;
}
@@ -21,6 +21,8 @@ export const Icon = ({ size = 4, name, className, ariaLabel }: IconProps) => {
// Cant just concatenate as TW wont pick up that the class is being used
// so below syntax is required
{
+ 'w-2 h-2': size === 2,
+ 'w-3 h-3': size === 3,
'w-4 h-4': size === 4,
'w-6 h-6': size === 6,
'w-8 h-8': size === 8,
diff --git a/libs/ui-toolkit/src/components/link/index.ts b/libs/ui-toolkit/src/components/link/index.ts
index 63b88256e..e33728e03 100644
--- a/libs/ui-toolkit/src/components/link/index.ts
+++ b/libs/ui-toolkit/src/components/link/index.ts
@@ -1 +1 @@
-export { Link } from './link';
+export * from './link';
diff --git a/libs/ui-toolkit/src/components/link/link.spec.tsx b/libs/ui-toolkit/src/components/link/link.spec.tsx
index 37f8621e2..389105dbf 100644
--- a/libs/ui-toolkit/src/components/link/link.spec.tsx
+++ b/libs/ui-toolkit/src/components/link/link.spec.tsx
@@ -1,34 +1,62 @@
import { render, screen } from '@testing-library/react';
-import { Link } from '.';
+import { ExternalLink, Link } from '.';
-it('renders a link with a text', () => {
- render(
-
- Link text
-
- );
- const link = screen.getByRole('link', { name: 'Link title' });
- expect(link).toBeInTheDocument();
- expect(link).toHaveAttribute('data-testid', 'link');
- expect(link).toHaveAttribute('referrerPolicy', 'strict-origin');
- expect(link).toHaveAttribute('href', '127.0.0.1');
- expect(link).toHaveAttribute('title', 'Link title');
- expect(link).toHaveClass('cursor-pointer');
- expect(link).toHaveClass('underline');
+describe('Link', () => {
+ it('renders a link with a text', () => {
+ render(
+
+ Link text
+
+ );
+ const link = screen.getByRole('link', { name: 'Link title' });
+ expect(link).toBeInTheDocument();
+ expect(link).toHaveAttribute('data-testid', 'link');
+ expect(link).toHaveAttribute('referrerPolicy', 'strict-origin');
+ expect(link).toHaveAttribute('href', '127.0.0.1');
+ expect(link).toHaveAttribute('title', 'Link title');
+ expect(link).toHaveClass('cursor-pointer');
+ expect(link).toHaveClass('underline');
+ });
+
+ it('renders a link with children elements', () => {
+ render(
+
+
Link text
+
+ );
+ const link = screen.getByRole('link', { name: 'Link title' });
+ expect(link).toBeInTheDocument();
+ expect(link).toHaveAttribute('data-testid', 'link');
+ expect(link).toHaveAttribute('referrerPolicy', 'strict-origin');
+ expect(link).toHaveAttribute('href', '127.0.0.1');
+ expect(link).toHaveAttribute('title', 'Link title');
+ expect(link).toHaveClass('cursor-pointer');
+ expect(link).not.toHaveClass('underline');
+ });
});
-it('renders a link with children elements', () => {
- render(
-
-
Link text
-
- );
- const link = screen.getByRole('link', { name: 'Link title' });
- expect(link).toBeInTheDocument();
- expect(link).toHaveAttribute('data-testid', 'link');
- expect(link).toHaveAttribute('referrerPolicy', 'strict-origin');
- expect(link).toHaveAttribute('href', '127.0.0.1');
- expect(link).toHaveAttribute('title', 'Link title');
- expect(link).toHaveClass('cursor-pointer');
- expect(link).not.toHaveClass('underline');
+describe('ExternalLink', () => {
+ it('should have an icon indicating that it is an external link', () => {
+ render(
Go to Vega);
+ const link = screen.getByTestId('external-link');
+ expect(link.children.length).toEqual(2);
+ expect(link.children[1].tagName.toUpperCase()).toEqual('SVG');
+ });
+
+ it('should have an underlined text part', () => {
+ render(
Go to Vega);
+ const link = screen.getByTestId('external-link');
+ expect(link.children[0]).toHaveClass('underline');
+ });
+
+ it('should not have an icon or underlined text if wrapping an element', () => {
+ render(
+
+ inner element
+
+ );
+ const link = screen.getByTestId('external-link');
+ expect(link.children.length).toEqual(1);
+ expect(link.children[0]).toHaveClass('inner');
+ });
});
diff --git a/libs/ui-toolkit/src/components/link/link.tsx b/libs/ui-toolkit/src/components/link/link.tsx
index 8d973f12b..b729017c5 100644
--- a/libs/ui-toolkit/src/components/link/link.tsx
+++ b/libs/ui-toolkit/src/components/link/link.tsx
@@ -1,5 +1,7 @@
+import { IconNames } from '@blueprintjs/icons';
import classNames from 'classnames';
import type { ReactNode, AnchorHTMLAttributes } from 'react';
+import { Icon } from '../icon';
type LinkProps = AnchorHTMLAttributes
& {
children?: ReactNode;
@@ -27,5 +29,27 @@ export const Link = ({ className, children, ...props }: LinkProps) => {
);
};
-
Link.displayName = 'Link';
+
+export const ExternalLink = ({ children, className, ...props }: LinkProps) => (
+
+ {typeof children === 'string' ? (
+ <>
+
+ {children}
+
+
+ >
+ ) : (
+ children
+ )}
+
+);
+ExternalLink.displayName = 'ExternalLink';