Compare commits

..
Author SHA1 Message Date
EddandMatthew Russell 996c4ac4d5 chore: regenerate types from version 66 (#2568)
* chore: regenerate types from version 66

* chore: fix transfer type mappings

* chore: update triggering ratio to use strings

* chore: regen explorer types

* build(explorer): fix linting error in regenerated explorer types

* chore: remove expiry fields from tests and fix imports to use updated generated code

Co-authored-by: Matthew Russell <mattrussell36@gmail.com>
2023-01-10 14:21:54 -08:00
mattrussell36 560e4a4040 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-10 18:06:26 +00:00
Matthew Russell d98ce18f9e chore: rename candles tab to chart (#2558) 2023-01-10 16:59:08 +01:00
m.ray 0fd1739ce5 fix(#2553): show rejection reason & orderbook fixed dp (#2563)
* fix: orderbook fixed dp - and show rejection reason

* fix: show rejection reason in order list

* fix: fix parked rejection reason test

* fix: remove not covered part
2023-01-10 13:41:37 +00:00
mattrussell36 cf43566bde chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-10 12:06:41 +00:00
mattrussell36 24a9712e91 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-10 06:08:21 +00:00
mattrussell36 03f5b5e78b chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-10 00:12:45 +00:00
Matthew Russell 9552fbc033 chore: change text for TRANSFER_TYPE_WIN (#2522) 2023-01-09 10:55:48 -08:00
mattrussell36 74a4a60195 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-09 18:06:34 +00:00
m.ray ef35999091 fix(#2532): show why market is in liquidity monitoring auction when liquidity supplied is > target (#2543)
* fix: add sufficient liquidity still auction message

* fix: add sufficient liquidity still auction message

* fix(#2532): update message

* fix(#2532): update liquidity data provider

* fix: lint issue

* fix: try update test
2023-01-09 14:39:03 +00:00
mattrussell36 cba44d7eb1 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-09 12:08:53 +00:00
Sam Keen c5b72e5a64 feat(2211): download proposal forms data as json (#2521)
* feat(2211): view proposal forms data as json

* feat(2211): removed the vega wallet barrier to viewing proposal forms

* feat(2211): tweaked the json viewing to download the proposal form json, with a useful title (proposal title and readable datetime)

* feat(2211): removed unwanted NX_SENTRY_DSN config from dev environments

* feat(2211): unit test for download-json.ts

* feat(2211): unit test for proposal-form-download-json.spec.tsx

* feat(2211): simplified unit test for proposal-form-download-json.spec.tsx

* feat(2211): removed unneeded unit test

* feat(2211): revoked change that was causing test failures
2023-01-09 09:48:47 +00:00
mattrussell36 863c288e0d chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-09 06:08:54 +00:00
mattrussell36 a97512cc7b chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-09 00:12:55 +00:00
mattrussell36 0884654c1e chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-08 18:07:31 +00:00
mattrussell36 5b4440f767 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-08 12:08:35 +00:00
mattrussell36 cfbea6e894 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-08 06:07:45 +00:00
mattrussell36 774a7d697f chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-08 00:13:00 +00:00
mattrussell36 dbb08acba3 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-07 18:07:40 +00:00
mattrussell36 6db201c1de chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-07 12:06:13 +00:00
mattrussell36 54cd8324ed chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-07 06:07:19 +00:00
mattrussell36 562e2b5cb2 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-07 00:10:12 +00:00
mattrussell36 ca2647d4d9 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-06 18:06:07 +00:00
m.rayandMatthew Russell bbdc64582a feat(#2465): vega-pink across frontend-monorepo (#2476)
* feat(#2465): change red to vega pink

* feat(#2465): change red to vega pink part 2

* fix: update vega.red to vega.pink

* feat: color the charts

* feat: color the charts

* feat: color the charts

* fix: use dark pink and green

* fix: use dark pink and green

* feat(#2467): color long/short toggle and place order button

* fix: colors wick showing within candle

* fix: remove opacity from chart

* fix: use vega dark pink and green for vol cell

* fix: toggle and button colors

* feat(#2465): toggle peer checked text white

* fix: add liquidity supplied gap-2 in tooltip data grid

* fix: add indicator temporarily

* chore: update colors

* chore: update from x-dark to vega-x

* fix: rename symbols

* chore: update sell candles to only use stroke as they are solidly filled

* fix: remove use state

* fix: remove network account types

Co-authored-by: Matthew Russell <mattrussell36@gmail.com>
2023-01-06 16:58:55 +00:00
m.rayandRado dabae31bfd fix(#2538): stake to ccy volume renaming (#2546)
* fix(#2538): stakeToCcyVolume param

* chore: fix for network params query error

Co-authored-by: Rado <szpiechrados@gmail.com>
2023-01-06 15:35:32 +00:00
Radosław Szpiech 5b42a6ad35 chore: update market.liquidity.stakeToCcyVolume in genesis file (#2545) 2023-01-06 15:21:35 +01:00
mattrussell36 870ae13b4c chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-06 12:07:43 +00:00
mattrussell36 4c32a21f28 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-06 06:08:04 +00:00
mattrussell36 2ea603e59e chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-06 00:10:00 +00:00
mattrussell36 3e485e3841 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-05 18:06:39 +00:00
daro-maj 7766b3f118 chore: update token e2e readme (#2504)
* chore: update readme for token-e2e tests setup

* chore: formatting fix

* chore: fix style

* chore: update readme for explorer-e2e tests

* chore: rework
2023-01-05 18:00:29 +01:00
Ciaran McGhie 8db3b01284 feat: add market close datetime to lp dashboard (#2529)
* feat: add proposal data from governance to market liquidity provider

We need data from this API to be able to tell when a market will close,
and when opening auctions will end.

* feat: add closing time to lp-dashboard market list page

Adds a 'closing time' column to the market list page on the dashboard.
2023-01-05 15:28:30 +00:00
Bartłomiej Głownia 4fbd2e5eba feat(#2323): don't allow cancel all if there are no cancellable orders (#2472) 2023-01-05 13:11:58 +00:00
Edd 53d3d5ac1c feat(explorer): improve empty states and loading indicators (#2496)
* feat(explorer): initial empty list component on block txs list

* feat(explorer): messages formatting

* chore(explorer): update generated types

* feat(explorer): empty state for markets and assets and governance and blocks and txs

* feat(explorer): use loader rather than the word loading

* feat(explorer): use loader rather than the word loading in more places

* feat(explorer): empty state appears below headers in more pages

* feat(explorer): txs per block update

* feat(explorer): update tests to match new messages

* test(explorer): add test for loading and empty states for assets

* test(explorer): add test for loading and empty states for more routes

* test(explorer): change loading detector
2023-01-05 13:10:42 +00:00
Matthew RussellandMadalina Raicu 35de756120 fix(#2515): use accounts nested under LP provision (#2523)
* fix: use accounts nested under lp provision

* fix: add getLiquidityProvision test

Co-authored-by: Madalina Raicu <madalina@raygroup.uk>
2023-01-05 13:09:45 +00:00
mattrussell36 f89cf31982 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-05 12:06:22 +00:00
mattrussell36 8976a40dc8 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-05 06:07:37 +00:00
mattrussell36 7669aeb218 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-05 00:10:03 +00:00
mattrussell36 6e996221b2 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-04 18:08:45 +00:00
botond 117c0c1306 fix: wallet connect save url to config (#2518) 2023-01-04 16:34:35 +00:00
daro-majandm.ray e56d7bc2d5 chore: cover ac 7003-MORD-016 by e2e test (#2514)
* chore: cover ac 7003-MORD-016 by e2e test

* chore: formatting fix

* Update apps/trading-e2e/src/integration/trading-orders.cy.ts

Co-authored-by: m.ray <16125548+MadalinaRaicu@users.noreply.github.com>

Co-authored-by: m.ray <16125548+MadalinaRaicu@users.noreply.github.com>
2023-01-04 16:04:28 +01:00
Dexter 85ec66a9e2 chore: update mirror URL 2023-01-04 14:31:28 +00:00
macqbat ba14ead8fc feat(1784): maintenance page (#2505)
* feat: maintance page

* feat: maintenance page - add styling and animations

* feat: maintenance page - add skip of node inits

* feat: maintenance page - add unit test

* feat: maintenance page - add unit test
2023-01-04 13:45:50 +01:00
Art 1211d27011 fix: error message consitency (2486) (#2507)
fix: error message consitency (2486)
2023-01-04 13:25:11 +01:00
mattrussell36 904a1b7805 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-04 12:08:46 +00:00
Dexter Edwards 66a8c659b4 chore: sentry dsn (#2499)
* chore: update readme to be correct

* chore: add sentry DSN to env files

* chore: use correct dsn
2023-01-04 09:16:37 +00:00
mattrussell36 f1a437500e chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-04 06:08:37 +00:00
mattrussell36 29ced0b460 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-04 00:10:49 +00:00
Art e45265ac71 chore: chain id to name (714) (#2503) 2023-01-03 14:54:54 -08:00
Art cc3c339cc3 fix: asset dialog overflow (2488) (#2497) 2023-01-03 10:37:23 -08:00
mattrussell36 6f95989569 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-03 18:07:04 +00:00
Radosław Szpiech 14f0c5a5fb chore: change connect vega wallet to set vega wallet config in local storage (#2502) 2023-01-03 14:56:33 +01:00
mattrussell36 0167a42990 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-03 12:06:25 +00:00
Joe Tsang 1d65c4791c chore: skip flow test (#2500) 2023-01-03 11:32:39 +00:00
mattrussell36 8a1fe6e5b1 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-03 06:08:12 +00:00
mattrussell36 437f7ef807 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-03 00:12:00 +00:00
mattrussell36 2b3683d4a4 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-02 18:07:24 +00:00
macqbat 6c84153cdb chore: redirect to last visited market instead first from the list (#2489)
* chore: redirect to last visited market instead first from the list

* chore: redirect to last visited market instead first from the list - add int tests

* feat: redirect to last visited market instead first from the list - refactor solution

* feat: redirect to last visited market instead first from the list - fix failing int test

* feat: redirect to last visited market instead first from the list - fix failing int test

* feat: redirect to last visited market instead first from the list - fix failing int test

* feat: redirect to last visited market instead first from the list - use immer in globalStore

* chore: redirect to last visited market - improve use of zustand
2023-01-02 17:01:06 +01:00
mattrussell36 ccce5a2848 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-02 12:08:44 +00:00
mattrussell36 5673620fbd chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-02 06:08:34 +00:00
mattrussell36 41d6940b89 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-02 00:12:58 +00:00
mattrussell36 84150bec8c chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-01 18:08:33 +00:00
mattrussell36 5a311d14c9 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-01 12:08:31 +00:00
mattrussell36 0f152a4b30 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-01 06:05:51 +00:00
mattrussell36 45d8b537a3 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-01 00:14:06 +00:00
mattrussell36 dc41be5715 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2022-12-31 18:08:31 +00:00
mattrussell36 a85cf66419 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2022-12-31 12:06:36 +00:00
mattrussell36 6e82e917ac chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2022-12-31 06:06:27 +00:00
mattrussell36 8dfdccd4aa chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2022-12-31 00:09:38 +00:00
Matthew Russell 82833cc06a chore: fix and improve types for market proposal (#2493)
* chore: fix and improve types for market proposal

* chore: remove unused type definition
2022-12-30 10:05:48 -08:00
botondandMatthew Russell aac3799b14 chore: add wallet client (#2462)
* chore: migrate to wallet client

* fix: bump client with new esm release version

* fix: add new no client error

* fix: bump wallet client to 0.1.2 and remove empty params from method calls

* fix: bump wallet client

* fix: format

* fix: reset client on url change

* fix: trading-deal-ticket tests after wallet client added

* fix: amend and cancel order tests, global connect tests

* chore: fix typescript error

* fix: connect wallet before mobile view test for console-lite

Co-authored-by: Matthew Russell <mattrussell36@gmail.com>
2022-12-30 10:05:27 -08:00
mattrussell36 0d1c9ff0f1 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2022-12-30 12:07:23 +00:00
Edd f8eec8a056 fix(explorer): fix resizing callout (#2492)
* fix(explorer): prevent layout thrashing on stats page
2022-12-30 11:40:47 +00:00
Edd ee6f26d473 feat(explorer): use block height filter 2022-12-30 09:53:07 +00:00
mattrussell36 de62d2d972 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2022-12-30 06:08:01 +00:00
Matthew Russell 955e233c46 fix: dark class being removed on token due to theme switcher changes (#2484)
* fix: dark class being removed on token due to theme switcher changes

* chore: check for window before reading from document classlist
2022-12-29 21:01:37 -08:00
Matthew RussellandEdd 0bafa4c7d5 chore: add readmes for token and explorer e2e (#2485)
* chore: add readmes for token and explorer e2e

* fix: typo fix in explorer readme

* fix: typo fix in token readme

Co-authored-by: Edd <edd@vega.xyz>
2022-12-29 20:48:04 -08:00
mattrussell36 045529dc38 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2022-12-30 00:11:08 +00:00
mattrussell36 5ca3e4d90f chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2022-12-29 18:08:27 +00:00
mattrussell36 9048d41f72 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2022-12-29 12:08:48 +00:00
mattrussell36 d731c4797c chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2022-12-29 06:08:36 +00:00
mattrussell36 4a931ca134 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2022-12-29 00:11:03 +00:00
mattrussell36 3398b15d8a chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2022-12-28 18:08:02 +00:00
m.rayandMatthew Russell 1e98ecbd21 feat(#2367): liquidity supplied info in market header (#2481)
* feat(#2367): market liquidity supplied in trade market header

* feat(#2467): calculate LP status

* fix: add LP view link

* fix: add LP view link

* feat(#2367): show liquidity supplied percentage

* feat(#2367): show liquidity supplied percentage

* fix: liquidity-utils test needs big number

* feat(#2456): liquidity status marker

* feat(#2456): liquidity indicator

* feat(#2367): update props lp

* fix: use market data directly

* feat(#2367): move data grid in react-helpers

* feat(#2367): move data grid in react-helpers

* fix: indicator commented

* chore: remove unnecessary styles

* test: update test name

Co-authored-by: Matthew Russell <mattrussell36@gmail.com>
2022-12-28 09:37:19 -08:00
daro-maj a9c7c2bb46 chore: cover7003 mord e2e tests (#2487)
* chore:  tests will be added after the proper implementation is prepared

* chore: formatting fix
2022-12-28 15:18:06 +01:00
mattrussell36 ba2c71de67 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2022-12-28 12:06:41 +00:00
mattrussell36 15d2aed343 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2022-12-28 06:08:30 +00:00
mattrussell36 0284eaf9a2 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2022-12-28 00:12:18 +00:00
208 changed files with 5410 additions and 2749 deletions
@@ -4,8 +4,8 @@ const marketName = 'ACTIVE MARKET';
describe('market selector', { tags: '@smoke' }, () => {
beforeEach(() => {
cy.mockConsole();
cy.setVegaWallet();
cy.visit(`/trading/${marketId}`);
cy.connectVegaWallet();
cy.wait('@Markets');
});
@@ -67,6 +67,7 @@ describe('market selector', { tags: '@smoke' }, () => {
it('mobile view', () => {
cy.viewport('iphone-xr');
cy.visit(`/trading/${marketId}`);
cy.connectVegaWallet();
cy.get('[role="dialog"]').should('not.exist');
cy.getByTestId('arrow-button').click();
cy.get('[role="dialog"]').should('be.visible');
@@ -30,7 +30,6 @@ describe('Market trade with wallet disconnected', { tags: '@smoke' }, () => {
cy.mockConsole();
cy.visit(`/trading/${marketId}`);
cy.wait('@Market');
console.log('marketId', marketId);
});
it('should not display steps', () => {
cy.getByTestId('trading-connect-wallet')
@@ -51,8 +50,8 @@ describe('Market trade', { tags: '@regression' }, () => {
cy.mockGQL((req) => {
aliasGQLQuery(req, 'Market', marketQuery(marketOverride));
});
cy.setVegaWallet();
cy.visit(`/trading/${marketId}`);
cy.connectVegaWallet();
cy.wait('@Market');
});
@@ -14,6 +14,7 @@ import {
describe('Portfolio page - wallet', { tags: '@smoke' }, () => {
it('button for wallet connect should work', () => {
cy.mockConsole();
cy.visit('/');
cy.get('[href="/portfolio"]').eq(0).click();
cy.getByTestId('trading-connect-wallet').should('be.visible');
@@ -34,11 +35,11 @@ describe('Portfolio page tabs', { tags: '@smoke' }, () => {
aliasGQLQuery(req, 'Accounts', accountsQuery());
aliasGQLQuery(req, 'Assets', assetsQuery());
});
cy.setVegaWallet();
});
it('certain tabs should exist', () => {
cy.visit('/portfolio');
cy.connectVegaWallet();
cy.getByTestId('assets').click();
cy.location('pathname').should('eq', '/portfolio/assets');
@@ -57,28 +58,15 @@ describe('Portfolio page tabs', { tags: '@smoke' }, () => {
});
describe('Assets view', () => {
before(() => {
cy.mockGQL((req) => {
aliasGQLQuery(req, 'ChainId', chainIdQuery());
aliasGQLQuery(req, 'Statistics', statisticsQuery());
aliasGQLQuery(req, 'Positions', positionsQuery());
aliasGQLQuery(req, 'Margins', marginsQuery());
aliasGQLQuery(req, 'Markets', marketsQuery());
aliasGQLQuery(req, 'MarketsData', marketsDataQuery());
aliasGQLQuery(req, 'Accounts', accountsQuery());
aliasGQLQuery(req, 'Assets', assetsQuery());
});
beforeEach(() => {
cy.mockConsole();
cy.setVegaWallet();
cy.visit('/portfolio/assets');
cy.connectVegaWallet();
});
it('data should be properly rendered', () => {
cy.get('.ag-center-cols-container .ag-row').should('have.length', 5);
cy.get(
'.ag-center-cols-container [row-id="ACCOUNT_TYPE_GENERAL-asset-id-null"]'
)
.find('button')
.click();
cy.get('[title="tEURO"] button').click();
cy.getByTestId('dialog-title').should(
'have.text',
'Asset details - tEURO'
@@ -99,8 +87,8 @@ describe('Portfolio page tabs', { tags: '@smoke' }, () => {
aliasGQLQuery(req, 'Accounts', accountsQuery());
aliasGQLQuery(req, 'Assets', assetsQuery());
});
cy.setVegaWallet();
cy.visit('/portfolio/positions');
cy.connectVegaWallet();
});
it('data should be properly rendered', () => {
@@ -116,8 +104,8 @@ describe('Portfolio page tabs', { tags: '@smoke' }, () => {
aliasGQLQuery(req, 'Orders', ordersQuery());
aliasGQLQuery(req, 'Markets', marketsQuery());
});
cy.setVegaWallet();
cy.visit('/portfolio/orders');
cy.connectVegaWallet();
});
it('data should be properly rendered', () => {
@@ -134,8 +122,8 @@ describe('Portfolio page tabs', { tags: '@smoke' }, () => {
aliasGQLQuery(req, 'Markets', marketsQuery());
aliasGQLQuery(req, 'Fills', fillsQuery());
});
cy.setVegaWallet();
cy.visit('/portfolio/fills');
cy.connectVegaWallet();
});
it('data should be properly rendered', () => {
@@ -161,8 +149,8 @@ describe('Portfolio page tabs', { tags: '@smoke' }, () => {
aliasGQLQuery(req, 'Margins', marginsQuery());
aliasGQLQuery(req, 'MarketsData', marketsDataQuery());
});
cy.setVegaWallet();
cy.visit('/portfolio');
cy.connectVegaWallet();
});
it('"No data to display" should be always displayed', () => {
@@ -13,6 +13,7 @@ import {
marketsCandlesQuery,
marketsDataQuery,
marketsQuery,
networkParamsQuery,
ordersQuery,
positionsQuery,
statisticsQuery,
@@ -47,6 +48,7 @@ const mockPage = (req: CyHttpMessages.IncomingHttpRequest) => {
aliasGQLQuery(req, 'SimpleMarkets', marketsQuery());
aliasGQLQuery(req, 'Orders', ordersQuery());
aliasGQLQuery(req, 'Fills', fillsQuery());
aliasGQLQuery(req, 'NetworkParams', networkParamsQuery());
};
export const addMockConsole = () => {
@@ -8,7 +8,6 @@ import {
useOrderMargin,
useMaximumPositionSize,
useCalculateSlippage,
validateAmount,
} from '@vegaprotocol/deal-ticket';
import { InputError } from '@vegaprotocol/ui-toolkit';
import { BigNumber } from 'bignumber.js';
@@ -23,6 +22,7 @@ import {
addDecimalsFormatNumber,
addDecimal,
formatNumber,
validateAmount,
} from '@vegaprotocol/react-helpers';
import {
useOrderSubmit,
@@ -1,13 +1,12 @@
import type { ReactNode } from 'react';
import type { FieldErrors } from 'react-hook-form';
import { useMemo } from 'react';
import { t, toDecimal } from '@vegaprotocol/react-helpers';
import { DataGrid, t, toDecimal } from '@vegaprotocol/react-helpers';
import { useVegaWallet } from '@vegaprotocol/wallet';
import * as Schema from '@vegaprotocol/types';
import type { OrderSubmissionBody } from '@vegaprotocol/wallet';
import { Tooltip } from '@vegaprotocol/ui-toolkit';
import {
MarketDataGrid,
compileGridData,
MarginWarning,
isMarketInAuction,
@@ -216,9 +215,7 @@ export const useOrderValidation = ({
<span>
{t('This market is in auction until it reaches')}{' '}
<Tooltip
description={
<MarketDataGrid grid={compileGridData(market)} />
}
description={<DataGrid grid={compileGridData(market)} />}
>
<span>{t('sufficient liquidity')}</span>
</Tooltip>
@@ -240,9 +237,7 @@ export const useOrderValidation = ({
<span>
{t('This market is in auction due to')}{' '}
<Tooltip
description={
<MarketDataGrid grid={compileGridData(market)} />
}
description={<DataGrid grid={compileGridData(market)} />}
>
<span>{t('high price volatility')}</span>
</Tooltip>
@@ -281,9 +276,7 @@ export const useOrderValidation = ({
<span>
{t('This market is in auction until it reaches')}{' '}
<Tooltip
description={
<MarketDataGrid grid={compileGridData(market)} />
}
description={<DataGrid grid={compileGridData(market)} />}
>
<span>{t('sufficient liquidity')}</span>
</Tooltip>
@@ -307,9 +300,7 @@ export const useOrderValidation = ({
<span>
{t('This market is in auction due to')}{' '}
<Tooltip
description={
<MarketDataGrid grid={compileGridData(market)} />
}
description={<DataGrid grid={compileGridData(market)} />}
>
<span>{t('high price volatility')}</span>
</Tooltip>
@@ -45,7 +45,6 @@ const AccountsManager = () => {
successCallback(rowsThisBlock, lastRow);
};
const { columnDefs, defaultColDef } = useAccountColumnDefinitions();
console.log(data, loading);
return (
<>
<AsyncRenderer
+1
View File
@@ -4,6 +4,7 @@ NX_TENDERMINT_URL=https://n04.d.vega.xyz/tm
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
# App flags
NX_EXPLORER_ASSETS=1
+1
View File
@@ -4,6 +4,7 @@ NX_TENDERMINT_URL=https://mainnet-observer-proxy01.ops.vega.xyz/
NX_TENDERMINT_WEBSOCKET_URL=wss://mainnet-observer-proxy01.ops.vega.xyz/websocket
NX_VEGA_URL=https://api.vega.xyz/query
NX_VEGA_ENV=MAINNET
NX_BLOCK_EXPLORER=https://be.explorer.vega.xyz/rest
# App flags
NX_EXPLORER_ASSETS=1
+1
View File
@@ -4,6 +4,7 @@ NX_TENDERMINT_URL=https://tm.n00.stagnet3.vega.xyz
NX_TENDERMINT_WEBSOCKET_URL=wss://tm.n00.stagnet3.vega.xyz/websocket
NX_VEGA_URL=https://api.stagnet3.vega.xyz/graphql
NX_VEGA_ENV=STAGNET3
NX_BLOCK_EXPLORER=https://be.stagnet3.vega.xyz/rest
# App flags
NX_EXPLORER_ASSETS=1
+1
View File
@@ -4,6 +4,7 @@ NX_TENDERMINT_URL=https://tm.n07.testnet.vega.xyz/tm
NX_TENDERMINT_WEBSOCKET_URL=wss://lb.testnet.vega.xyz/tm/websocket
NX_VEGA_URL=https://api.n11.testnet.vega.xyz/graphql
NX_VEGA_ENV=TESTNET
NX_BLOCK_EXPLORER=https://be.testnet.vega.xyz/rest
# App flags
NX_EXPLORER_ASSETS=1
+8 -3
View File
@@ -21,7 +21,12 @@ The e2e tests run against a locally running instance of the Vega network, manage
- Install the required Vega smart contracts
- Set up DataNodes with a running GraphQL and REST APIs.
Refer to the [Vega Capsule readme](https://github.com/vegaprotocol/vegacapsule#readme) for setting up and running Capsule. You will need [Go 1.19 or later](https://go.dev/doc/install) and [Docker](https://docs.docker.com/get-docker/) installed.
1. Refer to the [Vega Capsule readme](https://github.com/vegaprotocol/vegacapsule#readme) for setting up and running Capsule - follow by Pre-start and Quick Start (points 1-2)
2. Bootstrap with auto-installed dependencies including wallet
```bash
vegacapsule network bootstrap --config-path=../frontend-monorepo/vegacapsule/config.hcl --force
```
### Troubleshooting
@@ -29,6 +34,6 @@ Refer to the [Vega Capsule readme](https://github.com/vegaprotocol/vegacapsule#r
## Vega Wallet Setup
Start by [downloading the Vega wallet software here](https://github.com/vegaprotocol/vega/releases).
You can then refer to (or run) `frontend-monorepo/vegacapsule/setup-vegawallet.sh`. This will initialise and configure your wallet to have the correct public keys and network config to run against capsule.
You can then refer to (or run) `vegacapsule/setup-vegawallet.sh`. This will initialise and configure your wallet to have the correct public keys and network config to run against capsule.
Go to the .env file in `apps/explorer-e2e` and set the `CYPRESS_VEGA_WALLET_API_TOKEN` environment variable by pasting in your wallets long lived api token
@@ -29,7 +29,7 @@
"market.liquidity.maximumLiquidityFeeFactorLevel",
"market.liquidity.minimum.probabilityOfTrading.lpOrders",
"market.liquidity.probabilityOfTrading.tau.scaling",
"market.liquidity.stakeToCcySiskas",
"market.liquidity.stakeToCcyVolume",
"market.liquidity.targetstake.triggering.ratio",
"market.liquidityProvision.minLpStakeQuantumMultiple",
"market.liquidityProvision.shapes.maxSize",
@@ -52,7 +52,8 @@ context('Blocks page', { tags: '@regression' }, function () {
});
});
it('Previous button disabled on first block', function () {
// Skipping - see https://github.com/vegaprotocol/frontend-monorepo/issues/2494
it.skip('Previous button disabled on first block', function () {
cy.get('[data-testid="block-input"]').type('1');
cy.get('[data-testid="go-submit"]').click();
cy.get(previousBlockBtn).find('button').should('be.disabled');
@@ -115,7 +116,7 @@ context('Blocks page', { tags: '@regression' }, function () {
});
function waitForBlocksResponse() {
cy.contains('Loading...').should('not.exist', { timeout: 18000 });
cy.get('[data-testid="loader"]').should('not.exist', { timeout: 18000 });
}
function validateBlocksDisplayed() {
+19 -21
View File
@@ -20,19 +20,18 @@ context('Home Page', function () {
1: 'Height',
2: 'Uptime',
3: 'Total nodes',
4: 'Inactive nodes',
5: 'Total staked',
6: 'Backlog',
7: 'Trades / second',
8: 'Orders / block',
9: 'Orders / second',
10: 'Transactions / block',
11: 'Block time',
12: 'Time',
13: 'App',
14: 'Tendermint',
15: 'Up since',
16: 'Chain ID',
4: 'Total staked',
5: 'Backlog',
6: 'Trades / second',
7: 'Orders / block',
8: 'Orders / second',
9: 'Transactions / block',
10: 'Block time',
11: 'Time',
12: 'App',
13: 'Tendermint',
14: 'Up since',
15: 'Chain ID',
};
cy.get('[data-testid="stats-title"]')
@@ -40,7 +39,7 @@ context('Home Page', function () {
cy.wrap($list).should('have.text', statTitles[index]);
})
.then(($list) => {
cy.wrap($list).should('have.length', 17);
cy.wrap($list).should('have.length', 16);
});
cy.get(statsValue).eq(0).should('have.text', 'CONNECTED');
@@ -50,30 +49,29 @@ context('Home Page', function () {
.invoke('text')
.should('match', /\d+d \d+h \d+m \d+s/i);
cy.get(statsValue).eq(3).should('have.text', '2');
cy.get(statsValue).eq(4).should('have.text', '2');
cy.get(statsValue)
.eq(5)
.eq(4)
.invoke('text')
.should('match', /\d+\.\d\d(?!\d)/i);
cy.get(statsValue).eq(5).should('have.text', '0');
cy.get(statsValue).eq(6).should('have.text', '0');
cy.get(statsValue).eq(7).should('have.text', '0');
cy.get(statsValue).eq(8).should('have.text', '0');
cy.get(statsValue).eq(9).should('have.text', '0');
cy.get(statsValue).eq(9).should('not.be.empty');
cy.get(statsValue).eq(10).should('not.be.empty');
cy.get(statsValue).eq(11).should('not.be.empty');
cy.get(statsValue).eq(12).should('not.be.empty');
if (Cypress.env('NIGHTLY_RUN') != true) {
cy.get(statsValue)
.eq(13)
.eq(12)
.invoke('text')
.should('match', /v\d+\.\d+\.\d+/i);
}
cy.get(statsValue)
.eq(14)
.eq(13)
.invoke('text')
.should('match', /\d+\.\d+\.\d+/i);
cy.get(statsValue).eq(14).should('not.be.empty');
cy.get(statsValue).eq(15).should('not.be.empty');
cy.get(statsValue).eq(16).should('not.be.empty');
});
it('Block height should be updating', function () {
+1 -1
View File
@@ -70,7 +70,7 @@
"executor": "@nrwl/workspace:run-commands",
"options": {
"commands": [
"npx openapi-typescript https://raw.githubusercontent.com/vegaprotocol/documentation/main/specs/v0.62.1/blockexplorer.openapi.json --output apps/explorer/src/types/explorer.d.ts --immutable-types"
"npx openapi-typescript https://raw.githubusercontent.com/vegaprotocol/documentation/main/specs/v0.66.1/blockexplorer.openapi.json --output apps/explorer/src/types/explorer.d.ts --immutable-types"
]
}
},
@@ -59,7 +59,8 @@ describe('Blocks infinite list', () => {
error={undefined}
/>
);
expect(screen.getByText('No items')).toBeInTheDocument();
expect(screen.getByTestId('emptylist')).toBeInTheDocument();
expect(screen.getByText('This chain has 0 blocks')).toBeInTheDocument();
});
it('error is displayed at item level', () => {
@@ -4,6 +4,8 @@ import InfiniteLoader from 'react-window-infinite-loader';
import { t } from '@vegaprotocol/react-helpers';
import type { BlockMeta } from '../../routes/blocks/tendermint-blockchain-response';
import { BlockData } from './block-data';
import EmptyList from '../empty-list/empty-list';
import { Loader } from '@vegaprotocol/ui-toolkit';
interface BlocksInfiniteListProps {
hasMoreBlocks: boolean;
@@ -31,7 +33,16 @@ export const BlocksInfiniteList = ({
className,
}: BlocksInfiniteListProps) => {
if (!blocks) {
return <div>No items</div>;
if (!areBlocksLoading) {
return (
<EmptyList
heading={t('This chain has 0 blocks')}
label={t('Check back soon')}
/>
);
} else {
return <Loader />;
}
}
// If there are more items to be loaded then add an extra row to hold a loading indicator.
@@ -50,7 +61,7 @@ export const BlocksInfiniteList = ({
if (error) {
content = t(`${error}`);
} else if (!isItemLoaded(index)) {
content = t('Loading...');
content = <Loader />;
} else {
content = <BlockData block={blocks[index]} />;
}
@@ -0,0 +1,34 @@
export type EmptyListProps = {
heading?: string;
label?: string;
};
/**
* Renders the empty state from github ticket #1463
*/
const EmptyList = ({ heading, label }: EmptyListProps) => {
return (
<div
className="empty-list w-full items-center h-full align-center"
data-testid="emptylist"
>
<div className="skeleton-list border-dashed border-neutral-800 rounded p-5 w-full border-[1px] grid gap-4 grid-cols-9 grid-rows-1 place-content-around mb-4">
<div className="bg-neutral-900 mr-5 h-3 col-span-5"></div>
<div className="bg-neutral-900 h-3 col-span-1"></div>
</div>
<div className="mt-4">
{heading ? (
<h1 className="font-alpha text-xl uppercase text-center leading-relaxed">
{heading}
</h1>
) : null}
{label ? (
<p className="font-alpha text-gray-500 text-center">{label}</p>
) : null}
</div>
</div>
);
};
export default EmptyList;
@@ -14,8 +14,6 @@ export const methodText: Record<
METHOD_NOW: 'Immediate',
METHOD_UNSPECIFIED: 'Unspecified',
METHOD_AT_END_OF_EPOCH: 'End of epoch',
// This will be removed in a future release
METHOD_IN_ANGER: 'Immediate',
};
interface TxDetailsUndelegateProps {
@@ -2,4 +2,3 @@ export { TxList } from './tx-list';
export { TxOrderType } from './tx-order-type';
export { TxsInfiniteList } from './txs-infinite-list';
export { TxsInfiniteListItem } from './txs-infinite-list-item';
export { TxsStatsInfo } from './txs-stats-info';
@@ -137,8 +137,7 @@ export const TxOrderType = ({ orderType, command }: TxOrderTypeProps) => {
// This will get unwieldy and should probably produce a different colour of tag
if (type === 'Chain Event' && !!command?.chainEvent) {
type = getLabelForChainEvent(command.chainEvent);
colours =
'text-white dark-text-white bg-vega-pink-dark dark:bg-vega-pink-dark';
colours = 'text-white dark-text-white bg-vega-pink dark:bg-vega-pink';
} else if (type === 'Proposal' || type === 'Governance Proposal') {
if (command && !!command.proposalSubmission) {
type = getLabelForProposal(command.proposalSubmission);
@@ -46,7 +46,10 @@ describe('Txs infinite list', () => {
error={undefined}
/>
);
expect(screen.getByText('No items')).toBeInTheDocument();
expect(screen.getByTestId('emptylist')).toBeInTheDocument();
expect(
screen.getByText('This chain has 0 transactions')
).toBeInTheDocument();
});
it('error is displayed at item level', () => {
@@ -4,6 +4,8 @@ import InfiniteLoader from 'react-window-infinite-loader';
import { t, useScreenDimensions } from '@vegaprotocol/react-helpers';
import { TxsInfiniteListItem } from './txs-infinite-list-item';
import type { BlockExplorerTransactionResult } from '../../routes/types/block-explorer-response';
import EmptyList from '../empty-list/empty-list';
import { Loader } from '@vegaprotocol/ui-toolkit';
interface TxsInfiniteListProps {
hasMoreTxs: boolean;
@@ -29,7 +31,7 @@ const Item = ({ index, style, isLoading, error }: ItemProps) => {
if (error) {
content = t(`Cannot fetch transaction: ${error}`);
} else if (isLoading) {
content = t('Loading...');
content = <Loader />;
} else {
const {
hash,
@@ -68,7 +70,16 @@ export const TxsInfiniteList = ({
const isStacked = ['xs', 'sm', 'md', 'lg'].includes(screenSize);
if (!txs) {
return <div>No items</div>;
if (!areTxsLoading) {
return (
<EmptyList
heading={t('This chain has 0 transactions')}
label={t('Check back soon')}
/>
);
} else {
return <Loader />;
}
}
// If there are more items to be loaded then add an extra row to hold a loading indicator.
@@ -1,5 +1,4 @@
import { Routes } from '../../routes/route-names';
import { DATA_SOURCES } from '../../config';
import { RenderFetched } from '../render-fetched';
import { TruncatedLink } from '../truncate/truncated-link';
import { TxOrderType } from './tx-order-type';
@@ -8,6 +7,9 @@ import { t, useFetch } from '@vegaprotocol/react-helpers';
import type { BlockExplorerTransactions } from '../../routes/types/block-explorer-response';
import isNumber from 'lodash/isNumber';
import { ChainResponseCode } from './details/chain-response-code/chain-reponse.code';
import { getTxsDataUrl } from '../../hooks/use-txs-data';
import { Loader } from '@vegaprotocol/ui-toolkit';
import EmptyList from '../empty-list/empty-list';
interface TxsPerBlockProps {
blockHeight: string;
@@ -17,15 +19,11 @@ interface TxsPerBlockProps {
const truncateLength = 5;
export const TxsPerBlock = ({ blockHeight, txCount }: TxsPerBlockProps) => {
// TODO after https://github.com/vegaprotocol/vega/pull/6958/files is merged and deployed, use filter
// by block height instead
const filters = `filters[block.height]=${blockHeight}`;
const url = getTxsDataUrl({ limit: txCount.toString(), filters });
const {
state: { data, loading, error },
} = useFetch<BlockExplorerTransactions>(
`${
DATA_SOURCES.blockExplorerUrl
}/transactions?before=${blockHeight.toString()}.0&limit=${txCount}`
);
} = useFetch<BlockExplorerTransactions>(url);
return (
<RenderFetched error={error} loading={loading} className="text-body-large">
@@ -88,10 +86,13 @@ export const TxsPerBlock = ({ blockHeight, txCount }: TxsPerBlockProps) => {
</tbody>
</Table>
</div>
) : loading ? (
<Loader />
) : (
<div className="sr-only">
{t(`No transactions in block ${blockHeight}`)}
</div>
<EmptyList
heading={t('No transactions in this block')}
label={t('0 transactions')}
/>
)}
</RenderFetched>
);
@@ -1,77 +0,0 @@
import { t } from '@vegaprotocol/react-helpers';
import { useEffect } from 'react';
import { InfoBlock } from '../../components/info-block';
import { Panel } from '../../components/panel';
import { useExplorerStatsQuery } from './__generated__/Explorer-stats';
import type { ExplorerStatsFieldsFragment } from './__generated__/Explorer-stats';
interface StatsMap {
field: keyof ExplorerStatsFieldsFragment;
label: string;
info: string;
}
export const TXS_STATS_MAP: StatsMap[] = [
{
field: 'averageOrdersPerBlock',
label: t('Orders per block'),
info: t(
'Number of new orders processed in the last block. All orders derived from pegged orders and liquidity commitments count as a single order'
),
},
{
field: 'txPerBlock',
label: t('Transactions per block'),
info: t('Number of transactions processed in the last block'),
},
{
field: 'tradesPerSecond',
label: t('Trades per second'),
info: t('Number of trades processed in the last second'),
},
{
field: 'ordersPerSecond',
label: t('Order per second'),
info: t(
'Number of orders processed in the last second. All orders derived from pegged orders and liquidity commitments count as a single order'
),
},
];
interface TxsStatsInfoProps {
className?: string;
}
export const TxsStatsInfo = ({ className }: TxsStatsInfoProps) => {
const { data, startPolling, stopPolling } = useExplorerStatsQuery();
useEffect(() => {
startPolling(1000);
return () => stopPolling();
});
const gridStyles =
'grid grid-rows-2 gap-4 grid-cols-2 xl:gap-8 xl:grid-rows-1 xl:grid-cols-4';
return (
<Panel className={className}>
<section className={gridStyles}>
{TXS_STATS_MAP.map((field) => {
if (!data?.statistics) {
return null;
}
// Workaround for awkward typing
const title = data.statistics[field.field] || '';
return (
<InfoBlock
subtitle={field.label}
tooltipInfo={field.info}
title={title}
/>
);
})}
</section>
</Panel>
);
};
@@ -84,13 +84,13 @@ export const WithdrawalProgress = ({ id, txStatus }: TxsStatsInfoProps) => {
const classes = {
indicatorFailed:
'rounded-full transition duration-500 ease-in-out h-12 w-12 py-3 border-2 border-red-600 bg-red-600 text-center text-white font-bold leading-5',
'rounded-full transition duration-500 ease-in-out h-12 w-12 py-3 border-2 border-pink-600 bg-vega-pink-600 text-center text-white font-bold leading-5',
textFailed:
'absolute top-0 -ml-10 text-center mt-16 w-32 text-xs font-medium uppercase text-vega-red',
'absolute top-0 -ml-10 text-center mt-16 w-32 text-xs font-medium uppercase text-vega-pink',
indicatorComplete:
'rounded-full transition duration-500 ease-in-out h-12 w-12 py-3 border-2 border-vega-green-dark bg-vega-green-dark text-center text-white leading-5',
'rounded-full transition duration-500 ease-in-out h-12 w-12 py-3 border-2 border-vega-green bg-vega-green text-center text-white leading-5',
textComplete:
'absolute top-0 -ml-10 text-center mt-16 w-32 text-xs font-medium uppercase text-vega-green-dark',
'absolute top-0 -ml-10 text-center mt-16 w-32 text-xs font-medium uppercase text-vega-green',
indicatorIncomplete:
'rounded-full transition duration-500 ease-in-out h-12 w-12 py-3 border-2 border-gray-300 text-center leading-5',
textIncomplete:
@@ -140,7 +140,7 @@ export function WithdrawalProgressSeparator({
return (
<div
className={`flex-auto border-t-2 transition duration-500 ease-in-out ${
isComplete ? 'border-vega-green-dark' : 'border-gray-300'
isComplete ? 'border-vega-green' : 'border-gray-300'
}`}
></div>
);
@@ -0,0 +1,44 @@
import { MockedProvider } from '@apollo/client/testing';
import { render } from '@testing-library/react';
import { MemoryRouter } from 'react-router-dom';
import Assets from './index';
import type { MockedResponse } from '@apollo/client/testing';
import { ExplorerAssetDocument } from '../../components/links/asset-link/__generated__/Asset';
function renderComponent(mock: MockedResponse[]) {
return (
<MemoryRouter>
<MockedProvider mocks={mock}>
<Assets />
</MockedProvider>
</MemoryRouter>
);
}
describe('Assets index', () => {
it('Renders loader when loading', async () => {
const mock = {
request: {
query: ExplorerAssetDocument,
},
result: {
data: {},
},
};
const res = render(renderComponent([mock]));
expect(await res.findByTestId('loader')).toBeInTheDocument();
});
it('Renders EmptyList when loading completes and there are no results', async () => {
const mock = {
request: {
query: ExplorerAssetDocument,
},
result: {
data: {},
},
};
const res = render(renderComponent([mock]));
expect(await res.findByTestId('emptylist')).toBeInTheDocument();
});
});
+16 -7
View File
@@ -2,14 +2,15 @@ import { getNodes, t } from '@vegaprotocol/react-helpers';
import React from 'react';
import { RouteTitle } from '../../components/route-title';
import { SubHeading } from '../../components/sub-heading';
import { SyntaxHighlighter } from '@vegaprotocol/ui-toolkit';
import { Loader, SyntaxHighlighter } from '@vegaprotocol/ui-toolkit';
import { useExplorerAssetsQuery } from './__generated__/Assets';
import type { AssetsFieldsFragment } from './__generated__/Assets';
import { useScrollToLocation } from '../../hooks/scroll-to-location';
import { useDocumentTitle } from '../../hooks/use-document-title';
import EmptyList from '../../components/empty-list/empty-list';
const Assets = () => {
const { data } = useExplorerAssetsQuery();
const { data, loading } = useExplorerAssetsQuery();
useDocumentTitle(['Assets']);
useScrollToLocation();
@@ -17,17 +18,25 @@ const Assets = () => {
const assets = getNodes<AssetsFieldsFragment>(data?.assetsConnection);
if (!assets || assets.length === 0) {
return <section></section>;
if (!loading) {
return (
<section>
<RouteTitle data-testid="assets-header">{t('Assets')}</RouteTitle>
<EmptyList
heading={t('This chain has no assets')}
label={t('0 assets')}
/>
</section>
);
} else {
return <Loader />;
}
}
return (
<section>
<RouteTitle data-testid="assets-header">{t('Assets')}</RouteTitle>
{assets.map((a) => {
if (!a) {
return null;
}
return (
<React.Fragment key={a.id}>
<SubHeading data-testid="asset-header" id={a.id}>
@@ -18,6 +18,7 @@ import { RenderFetched } from '../../../components/render-fetched';
import { t, useFetch } from '@vegaprotocol/react-helpers';
import { NodeLink } from '../../../components/links';
import { useDocumentTitle } from '../../../hooks/use-document-title';
import EmptyList from '../../../components/empty-list/empty-list';
const Block = () => {
const { block } = useParams<{ block: string }>();
@@ -112,7 +113,12 @@ const Block = () => {
blockHeight={blockData.result.block.header.height}
txCount={blockData.result.block.data.txs.length}
/>
) : null}
) : (
<EmptyList
heading={t('This block is empty')}
label={t('0 transactions')}
/>
)}
</>
)}
</>
@@ -1,6 +1,6 @@
import { t, useFetch } from '@vegaprotocol/react-helpers';
import { RouteTitle } from '../../components/route-title';
import { SyntaxHighlighter } from '@vegaprotocol/ui-toolkit';
import { Loader, SyntaxHighlighter } from '@vegaprotocol/ui-toolkit';
import { DATA_SOURCES } from '../../config';
import type { TendermintGenesisResponse } from './tendermint-genesis-response';
import { useDocumentTitle } from '../../hooks/use-document-title';
@@ -9,11 +9,16 @@ const Genesis = () => {
useDocumentTitle(['Genesis']);
const {
state: { data: genesis },
state: { data: genesis, loading },
} = useFetch<TendermintGenesisResponse>(
`${DATA_SOURCES.tendermintUrl}/genesis`
);
if (!genesis?.result.genesis) return null;
if (!genesis?.result.genesis) {
if (loading) {
return <Loader />;
}
return null;
}
return (
<section>
<RouteTitle data-testid="genesis-header">{t('Genesis')}</RouteTitle>
@@ -2,19 +2,35 @@ import { t } from '@vegaprotocol/react-helpers';
import React from 'react';
import { RouteTitle } from '../../components/route-title';
import { SubHeading } from '../../components/sub-heading';
import { SyntaxHighlighter } from '@vegaprotocol/ui-toolkit';
import { Loader, SyntaxHighlighter } from '@vegaprotocol/ui-toolkit';
import { useExplorerProposalsQuery } from './__generated__/Proposals';
import { useDocumentTitle } from '../../hooks/use-document-title';
import EmptyList from '../../components/empty-list/empty-list';
const Governance = () => {
const { data } = useExplorerProposalsQuery({
const { data, loading } = useExplorerProposalsQuery({
errorPolicy: 'ignore',
});
useDocumentTitle();
if (!data || !data.proposalsConnection || !data.proposalsConnection.edges) {
return <section></section>;
if (!loading) {
return (
<section>
<RouteTitle data-testid="governance-header">
{t('Governance Proposals')}
</RouteTitle>
<EmptyList
heading={t('This chain has no proposals')}
label={t('0 proposals')}
/>
</section>
);
} else {
return <Loader />;
}
}
const proposals = data?.proposalsConnection?.edges.map((e) => {
@@ -6,7 +6,7 @@ const defaultOptions = {} as const;
export type ExplorerMarketsQueryVariables = Types.Exact<{ [key: string]: never; }>;
export type ExplorerMarketsQuery = { __typename?: 'Query', marketsConnection?: { __typename?: 'MarketConnection', edges: Array<{ __typename?: 'MarketEdge', node: { __typename?: 'Market', id: string, decimalPlaces: number, tradingMode: Types.MarketTradingMode, state: Types.MarketState, fees: { __typename?: 'Fees', factors: { __typename?: 'FeeFactors', makerFee: string, infrastructureFee: string, liquidityFee: string } }, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', name: string, code: string, metadata: { __typename?: 'InstrumentMetadata', tags?: Array<string> | null }, product: { __typename?: 'Future', settlementAsset: { __typename?: 'Asset', id: string, name: string, decimals: number, globalRewardPoolAccount?: { __typename?: 'AccountBalance', balance: string } | null } } }, riskModel: { __typename?: 'LogNormalRiskModel', tau: number, riskAversionParameter: number, params: { __typename?: 'LogNormalModelParams', r: number, sigma: number, mu: number } } | { __typename?: 'SimpleRiskModel', params: { __typename?: 'SimpleRiskModelParams', factorLong: number, factorShort: number } }, marginCalculator?: { __typename?: 'MarginCalculator', scalingFactors: { __typename?: 'ScalingFactors', searchLevel: number, initialMargin: number, collateralRelease: number } } | null }, openingAuction: { __typename?: 'AuctionDuration', durationSecs: number, volume: number }, priceMonitoringSettings: { __typename?: 'PriceMonitoringSettings', parameters?: { __typename?: 'PriceMonitoringParameters', triggers?: Array<{ __typename?: 'PriceMonitoringTrigger', horizonSecs: number, probability: number, auctionExtensionSecs: number }> | null } | null }, liquidityMonitoringParameters: { __typename?: 'LiquidityMonitoringParameters', triggeringRatio: number, targetStakeParameters: { __typename?: 'TargetStakeParameters', timeWindow: number, scalingFactor: number } }, proposal?: { __typename?: 'Proposal', id?: string | null } | null, accountsConnection?: { __typename?: 'AccountsConnection', edges?: Array<{ __typename?: 'AccountEdge', node: { __typename?: 'AccountBalance', balance: string, type: Types.AccountType, asset: { __typename?: 'Asset', id: string, name: string } } } | null> | null } | null, data?: { __typename?: 'MarketData', markPrice: string, bestBidPrice: string, bestBidVolume: string, bestOfferPrice: string, bestOfferVolume: string, bestStaticBidPrice: string, bestStaticBidVolume: string, bestStaticOfferPrice: string, bestStaticOfferVolume: string, midPrice: string, staticMidPrice: string, timestamp: any, openInterest: string, auctionEnd?: string | null, auctionStart?: string | null, indicativePrice: string, indicativeVolume: string, trigger: Types.AuctionTrigger, extensionTrigger: Types.AuctionTrigger, targetStake?: string | null, suppliedStake?: string | null, marketValueProxy: string, priceMonitoringBounds?: Array<{ __typename?: 'PriceMonitoringBounds', minValidPrice: string, maxValidPrice: string, referencePrice: string, trigger: { __typename?: 'PriceMonitoringTrigger', auctionExtensionSecs: number, probability: number } }> | null, liquidityProviderFeeShare?: Array<{ __typename?: 'LiquidityProviderFeeShare', equityLikeShare: string, averageEntryValuation: string, party: { __typename?: 'Party', id: string } }> | null } | null } }> } | null };
export type ExplorerMarketsQuery = { __typename?: 'Query', marketsConnection?: { __typename?: 'MarketConnection', edges: Array<{ __typename?: 'MarketEdge', node: { __typename?: 'Market', id: string, decimalPlaces: number, tradingMode: Types.MarketTradingMode, state: Types.MarketState, fees: { __typename?: 'Fees', factors: { __typename?: 'FeeFactors', makerFee: string, infrastructureFee: string, liquidityFee: string } }, tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', name: string, code: string, metadata: { __typename?: 'InstrumentMetadata', tags?: Array<string> | null }, product: { __typename?: 'Future', settlementAsset: { __typename?: 'Asset', id: string, name: string, decimals: number, globalRewardPoolAccount?: { __typename?: 'AccountBalance', balance: string } | null } } }, riskModel: { __typename?: 'LogNormalRiskModel', tau: number, riskAversionParameter: number, params: { __typename?: 'LogNormalModelParams', r: number, sigma: number, mu: number } } | { __typename?: 'SimpleRiskModel', params: { __typename?: 'SimpleRiskModelParams', factorLong: number, factorShort: number } }, marginCalculator?: { __typename?: 'MarginCalculator', scalingFactors: { __typename?: 'ScalingFactors', searchLevel: number, initialMargin: number, collateralRelease: number } } | null }, openingAuction: { __typename?: 'AuctionDuration', durationSecs: number, volume: number }, priceMonitoringSettings: { __typename?: 'PriceMonitoringSettings', parameters?: { __typename?: 'PriceMonitoringParameters', triggers?: Array<{ __typename?: 'PriceMonitoringTrigger', horizonSecs: number, probability: number, auctionExtensionSecs: number }> | null } | null }, liquidityMonitoringParameters: { __typename?: 'LiquidityMonitoringParameters', triggeringRatio: string, targetStakeParameters: { __typename?: 'TargetStakeParameters', timeWindow: number, scalingFactor: number } }, proposal?: { __typename?: 'Proposal', id?: string | null } | null, accountsConnection?: { __typename?: 'AccountsConnection', edges?: Array<{ __typename?: 'AccountEdge', node: { __typename?: 'AccountBalance', balance: string, type: Types.AccountType, asset: { __typename?: 'Asset', id: string, name: string } } } | null> | null } | null, data?: { __typename?: 'MarketData', markPrice: string, bestBidPrice: string, bestBidVolume: string, bestOfferPrice: string, bestOfferVolume: string, bestStaticBidPrice: string, bestStaticBidVolume: string, bestStaticOfferPrice: string, bestStaticOfferVolume: string, midPrice: string, staticMidPrice: string, timestamp: any, openInterest: string, auctionEnd?: string | null, auctionStart?: string | null, indicativePrice: string, indicativeVolume: string, trigger: Types.AuctionTrigger, extensionTrigger: Types.AuctionTrigger, targetStake?: string | null, suppliedStake?: string | null, marketValueProxy: string, priceMonitoringBounds?: Array<{ __typename?: 'PriceMonitoringBounds', minValidPrice: string, maxValidPrice: string, referencePrice: string, trigger: { __typename?: 'PriceMonitoringTrigger', auctionExtensionSecs: number, probability: number } }> | null, liquidityProviderFeeShare?: Array<{ __typename?: 'LiquidityProviderFeeShare', equityLikeShare: string, averageEntryValuation: string, party: { __typename?: 'Party', id: string } }> | null } | null } }> } | null };
export const ExplorerMarketsDocument = gql`
@@ -0,0 +1,48 @@
import { MockedProvider } from '@apollo/client/testing';
import { render } from '@testing-library/react';
import { MemoryRouter } from 'react-router-dom';
import Markets from './index';
import type { MockedResponse } from '@apollo/client/testing';
import { ExplorerMarketsDocument } from './__generated__/Markets';
function renderComponent(mock: MockedResponse[]) {
return (
<MemoryRouter>
<MockedProvider mocks={mock}>
<Markets />
</MockedProvider>
</MemoryRouter>
);
}
describe('Markets index', () => {
it('Renders loader when loading', async () => {
const mock = {
request: {
query: ExplorerMarketsDocument,
},
result: {
data: {
marketsConnection: [],
},
},
};
const res = render(renderComponent([mock]));
expect(await res.findByTestId('loader')).toBeInTheDocument();
});
it('Renders EmptyList when loading completes and there are no results', async () => {
const mock = {
request: {
query: ExplorerMarketsDocument,
},
result: {
data: {
marketsConnection: [],
},
},
};
const res = render(renderComponent([mock]));
expect(await res.findByTestId('emptylist')).toBeInTheDocument();
});
});
+20 -12
View File
@@ -1,14 +1,15 @@
import React from 'react';
import { SyntaxHighlighter } from '@vegaprotocol/ui-toolkit';
import { Loader, SyntaxHighlighter } from '@vegaprotocol/ui-toolkit';
import { RouteTitle } from '../../components/route-title';
import { SubHeading } from '../../components/sub-heading';
import { t } from '@vegaprotocol/react-helpers';
import { useExplorerMarketsQuery } from './__generated__/Markets';
import { useScrollToLocation } from '../../hooks/scroll-to-location';
import { useDocumentTitle } from '../../hooks/use-document-title';
import EmptyList from '../../components/empty-list/empty-list';
const Markets = () => {
const { data } = useExplorerMarketsQuery();
const { data, loading } = useExplorerMarketsQuery();
useScrollToLocation();
useDocumentTitle(['Markets']);
@@ -19,16 +20,23 @@ const Markets = () => {
<section key="markets">
<RouteTitle data-testid="markets-heading">{t('Markets')}</RouteTitle>
{m
? m.map((e) => (
<React.Fragment key={e.node.id}>
<SubHeading data-testid="markets-header" id={e.node.id}>
{e.node.tradableInstrument.instrument.name}
</SubHeading>
<SyntaxHighlighter data={e.node} />
</React.Fragment>
))
: null}
{m ? (
m.map((e) => (
<React.Fragment key={e.node.id}>
<SubHeading data-testid="markets-header" id={e.node.id}>
{e.node.tradableInstrument.instrument.name}
</SubHeading>
<SyntaxHighlighter data={e.node} />
</React.Fragment>
))
) : loading ? (
<Loader />
) : (
<EmptyList
heading={t('This chain has no markets')}
label={t('0 markets')}
/>
)}
</section>
);
};
@@ -1,7 +1,7 @@
import { t } from '@vegaprotocol/react-helpers';
import { RouteTitle } from '../../../components/route-title';
import { BlocksRefetch } from '../../../components/blocks';
import { TxsInfiniteList, TxsStatsInfo } from '../../../components/txs';
import { TxsInfiniteList } from '../../../components/txs';
import { useTxsData } from '../../../hooks/use-txs-data';
import { useDocumentTitle } from '../../../hooks/use-document-title';
@@ -16,7 +16,6 @@ export const TxsList = () => {
<section className="md:p-2 lg:p-4 xl:p-6">
<RouteTitle>{t('Transactions')}</RouteTitle>
<BlocksRefetch refetch={refreshTxs} />
<TxsStatsInfo className="!my-12 py-8" />
<TxsInfiniteList
hasMoreTxs={hasMoreTxs}
areTxsLoading={loading}
@@ -1,8 +1,7 @@
import { t } from '@vegaprotocol/react-helpers';
import React from 'react';
import { RouteTitle } from '../../components/route-title';
import { SubHeading } from '../../components/sub-heading';
import { SyntaxHighlighter } from '@vegaprotocol/ui-toolkit';
import { Loader, SyntaxHighlighter } from '@vegaprotocol/ui-toolkit';
import { DATA_SOURCES } from '../../config';
import { useFetch } from '@vegaprotocol/react-helpers';
import type { TendermintValidatorsResponse } from './tendermint-validator-response';
@@ -28,7 +27,9 @@ const Validators = () => {
<SubHeading data-testid="vega-header">{t('Vega data')}</SubHeading>
<SyntaxHighlighter data-testid="vega-data" data={data} />
</>
) : null}
) : (
<Loader />
)}
{validators ? (
<>
<SubHeading data-testid="tendermint-header">
@@ -36,7 +37,9 @@ const Validators = () => {
</SubHeading>
<SyntaxHighlighter data-testid="tendermint-data" data={validators} />
</>
) : null}
) : (
<Loader />
)}
</section>
);
};
+110 -32
View File
@@ -14,9 +14,16 @@ type OneOf<T extends any[]> = T extends [infer Only]
: T extends [infer A, infer B, ...infer Rest]
? OneOf<[XOR<A, B>, ...Rest]>
: never;
/* typescript-eslint:enable no-explicit-any */
/* eslint-enable @typescript-eslint/no-explicit-any */
export interface paths {
'/info': {
/**
* Info
* @description Retrieves information about the block explorer.
* Response contains a semver formatted version of the data node and the commit hash, from which the block explorer was built,
*/
get: operations['BlockExplorer_Info'];
};
'/transactions': {
/**
* List transactions
@@ -33,6 +40,8 @@ export interface paths {
};
}
export type webhooks = Record<string, never>;
export interface components {
schemas: {
/**
@@ -100,8 +109,7 @@ export interface components {
readonly UndelegateSubmissionMethod:
| 'METHOD_UNSPECIFIED'
| 'METHOD_NOW'
| 'METHOD_AT_END_OF_EPOCH'
| 'METHOD_IN_ANGER';
| 'METHOD_AT_END_OF_EPOCH';
readonly blockexplorerapiv1Transaction: {
/**
* The height of the block the transaction was found in
@@ -117,6 +125,11 @@ export interface components {
readonly command?: components['schemas']['v1InputData'];
/** The cursor for this transaction (in the page, used for paginated results) */
readonly cursor?: string;
/**
* An optional error happening when processing / checking the transaction
* Should be set if error code is not 0
*/
readonly error?: string;
/** The hash of the transaction */
readonly hash?: string;
/**
@@ -124,6 +137,8 @@ export interface components {
* Format: int64
*/
readonly index?: number;
/** Submitter's signature of transaction */
readonly signature?: components['schemas']['v1Signature'];
/** The submitter of the transaction (Vega public key) */
readonly submitter?: string;
/** The type of transaction */
@@ -159,7 +174,7 @@ export interface components {
readonly '@type'?: string;
[key: string]: unknown | undefined;
};
/** Used announce a node as a new potential validator */
/** Used announce a node as a new pending validator */
readonly v1AnnounceNode: {
/** AvatarURL of the validator */
readonly avatarUrl?: string;
@@ -192,7 +207,7 @@ export interface components {
* Format: int64
*/
readonly vegaPubKeyIndex?: number;
/** Signature from the validator made using the vega wallet */
/** Signature from the validator made using the Vega wallet */
readonly vegaSignature?: components['schemas']['v1Signature'];
};
/**
@@ -287,6 +302,12 @@ export interface components {
/** The transaction corresponding to the hash */
readonly transaction?: components['schemas']['blockexplorerapiv1Transaction'];
};
readonly v1InfoResponse: {
/** The commit hash from which the data-node was built */
readonly commitHash?: string;
/** A semver formatted version of the data node */
readonly version?: string;
};
readonly v1InputData: {
readonly announceNode?: components['schemas']['v1AnnounceNode'];
readonly batchMarketInstructions?: components['schemas']['v1BatchMarketInstructions'];
@@ -351,7 +372,7 @@ export interface components {
/** The ID of the node that will be signed in or out of the smartcontract */
readonly validatorNodeId?: string;
};
/** A transaction to allow validator to rotate their vega keys */
/** A transaction to allow validator to rotate their Vega keys */
readonly v1KeyRotateSubmission: {
/** Hash of currently used public key */
readonly currentPubKeyHash?: string;
@@ -414,7 +435,7 @@ export interface components {
readonly sig?: string;
};
/**
* The kind of the signature created by a node, for example, allow-listing a new asset, withdrawal etc
* The kind of signature created by a node, for example, allow-listing a new asset, withdrawal etc
* @description - NODE_SIGNATURE_KIND_UNSPECIFIED: Represents an unspecified or missing value from the input
* - NODE_SIGNATURE_KIND_ASSET_NEW: Represents a signature for a new asset allow-listing
* - NODE_SIGNATURE_KIND_ASSET_WITHDRAWAL: Represents a signature for an asset withdrawal
@@ -432,13 +453,46 @@ export interface components {
| 'NODE_SIGNATURE_KIND_ERC20_MULTISIG_SIGNER_REMOVED'
| 'NODE_SIGNATURE_KIND_ASSET_UPDATE';
/**
* Used when a node votes for validating a given resource exists or is valid,
* Used when a node votes for validating that a given resource exists or is valid,
* for example, an ERC20 deposit is valid and exists on ethereum
*/
readonly v1NodeVote: {
/** Reference, required field */
readonly reference?: string;
/** type of NodeVote, also required */
readonly type?: components['schemas']['v1NodeVoteType'];
};
/**
* - TYPE_UNSPECIFIED: Represents an unspecified or missing value from the input
* - TYPE_STAKE_DEPOSITED: A node vote a new stake deposit
* - TYPE_STAKE_REMOVED: A node vote for a new stake removed event
* - TYPE_FUNDS_DEPOSITED: A node vote for new collateral deposited
* - TYPE_SIGNER_ADDED: A node vote for a new signer added to the erc20 bridge
* - TYPE_SIGNER_REMOVED: A node vote for a signer removed from the erc20 bridge
* - TYPE_BRIDGE_STOPPED: A node vote for a bridge stopped event
* - TYPE_BRIDGE_RESUMED: A node vote for a bridge resumed event
* - TYPE_ASSET_LISTED: A node vote for a newly listed asset
* - TYPE_LIMITS_UPDATED: A node vote for an asset limits update
* - TYPE_STAKE_TOTAL_SUPPLY: A node vote to share the total supply of the staking token
* - TYPE_SIGNER_THRESHOLD_SET: A node vote to update the threshold of the signer set for the multisig contract
* - TYPE_GOVERNANCE_VALIDATE_ASSET: A node vote to validate a new assert governance proposal
* @default TYPE_UNSPECIFIED
* @enum {string}
*/
readonly v1NodeVoteType:
| 'TYPE_UNSPECIFIED'
| 'TYPE_STAKE_DEPOSITED'
| 'TYPE_STAKE_REMOVED'
| 'TYPE_FUNDS_DEPOSITED'
| 'TYPE_SIGNER_ADDED'
| 'TYPE_SIGNER_REMOVED'
| 'TYPE_BRIDGE_STOPPED'
| 'TYPE_BRIDGE_RESUMED'
| 'TYPE_ASSET_LISTED'
| 'TYPE_LIMITS_UPDATED'
| 'TYPE_STAKE_TOTAL_SUPPLY'
| 'TYPE_SIGNER_THRESHOLD_SET'
| 'TYPE_GOVERNANCE_VALIDATE_ASSET';
/** Specific details for a one off transfer */
readonly v1OneOffTransfer: {
/**
@@ -553,6 +607,12 @@ export interface components {
readonly v1PropertyKey: {
/** @description name is the name of the property. */
readonly name?: string;
/**
* An optional decimal place to be be applied on the provided value
* valid only for PropertyType of type DECIMAL and INTEGER
* Format: uint64
*/
readonly numberDecimalPlaces?: string;
/** @description type is the type of the property. */
readonly type?: components['schemas']['v1PropertyKeyType'];
};
@@ -596,7 +656,7 @@ export interface components {
* Format: uint64
*/
readonly upgradeBlockHeight?: string;
/** the release tag for the vega binary */
/** the release tag for the Vega binary */
readonly vegaReleaseTag?: string;
};
/**
@@ -659,8 +719,8 @@ export interface components {
readonly nodeId?: string;
};
/**
* A message from a validator signaling they are still online and validating blocks
* or ready to validate block when they are till a potential validator
* A message from a validator signalling they are still online and validating blocks
* or ready to validate blocks when they are still a pending validator
*/
readonly v1ValidatorHeartbeat: {
/** Signature from the validator made using the ethereum wallet */
@@ -1061,11 +1121,6 @@ export interface components {
readonly quoteName?: string;
/** Asset ID for the product's settlement asset */
readonly settlementAsset?: string;
/**
* The number of decimal places implied by the settlement data (such as price) emitted by the settlement data source
* Format: int64
*/
readonly settlementDataDecimals?: number;
};
/** Instrument configuration */
readonly vegaInstrumentConfiguration: {
@@ -1090,11 +1145,8 @@ export interface components {
readonly auctionExtension?: string;
/** Specifies parameters related to target stake calculation */
readonly targetStakeParameters?: components['schemas']['vegaTargetStakeParameters'];
/**
* Specifies the triggering ratio for entering liquidity auction
* Format: double
*/
readonly triggeringRatio?: number;
/** Specifies the triggering ratio for entering liquidity auction */
readonly triggeringRatio?: string;
};
/** Represents a liquidity order */
readonly vegaLiquidityOrder: {
@@ -1111,17 +1163,17 @@ export interface components {
/** Risk model parameters for log normal */
readonly vegaLogNormalModelParams: {
/**
* Mu param
* Mu parameter, annualised growth rate of the underlying asset
* Format: double
*/
readonly mu?: number;
/**
* R param
* R parameter, annualised growth rate of the risk-free asset, used for discounting of future cash flows, can be any real number
* Format: double
*/
readonly r?: number;
/**
* Sigma param
* Sigma parameter, annualised volatility of the underlying asset, must be a strictly non-negative real number
* Format: double
*/
readonly sigma?: number;
@@ -1136,7 +1188,7 @@ export interface components {
*/
readonly riskAversionParameter?: number;
/**
* Tau
* Tau parameter of the risk model, projection horizon measured as a year fraction used in the expected shortfall calculation to obtain the maintenance margin, must be a strictly non-negative real number
* Format: double
*/
readonly tau?: number;
@@ -1180,6 +1232,11 @@ export interface components {
readonly liquidityMonitoringParameters?: components['schemas']['vegaLiquidityMonitoringParameters'];
/** Log normal risk model parameters, valid only if MODEL_LOG_NORMAL is selected */
readonly logNormal?: components['schemas']['vegaLogNormalRiskModel'];
/**
* Percentage move up and down from the mid price which specifies the range of
* price levels over which automated liquidity provision orders will be deployed
*/
readonly lpPriceRange?: string;
/** Optional new market meta data, tags */
readonly metadata?: readonly string[];
/**
@@ -1239,7 +1296,7 @@ export interface components {
readonly vegaPriceMonitoringTrigger: {
/**
* Price monitoring auction extension duration in seconds should the price
* breach it's theoretical level over the specified horizon at the specified
* breach its theoretical level over the specified horizon at the specified
* probability level
* Format: int64
*/
@@ -1436,11 +1493,6 @@ export interface components {
readonly dataSourceSpecForTradingTermination?: components['schemas']['vegaDataSourceDefinition'];
/** Human-readable name/abbreviation of the quote name */
readonly quoteName?: string;
/**
* The number of decimal places implied by the settlement data (such as price) emitted by the settlement external data source
* Format: int64
*/
readonly settlementDataDecimals?: number;
};
/** Instrument configuration */
readonly vegaUpdateInstrumentConfiguration: {
@@ -1464,6 +1516,11 @@ export interface components {
readonly liquidityMonitoringParameters?: components['schemas']['vegaLiquidityMonitoringParameters'];
/** Log normal risk model parameters, valid only if MODEL_LOG_NORMAL is selected */
readonly logNormal?: components['schemas']['vegaLogNormalRiskModel'];
/**
* Percentage move up and down from the mid price which specifies the range of
* price levels over which automated liquidity provision orders will be deployed
*/
readonly lpPriceRange?: string;
/** Optional market metadata, tags */
readonly metadata?: readonly string[];
/** Price monitoring parameters */
@@ -1504,6 +1561,27 @@ export interface components {
export type external = Record<string, never>;
export interface operations {
BlockExplorer_Info: {
/**
* Info
* @description Retrieves information about the block explorer.
* Response contains a semver formatted version of the data node and the commit hash, from which the block explorer was built,
*/
responses: {
/** @description A successful response. */
200: {
content: {
readonly 'application/json': components['schemas']['v1InfoResponse'];
};
};
/** @description An unexpected error response. */
default: {
content: {
readonly 'application/json': components['schemas']['googlerpcStatus'];
};
};
};
};
BlockExplorer_ListTransactions: {
/**
* List transactions
@@ -10,6 +10,7 @@ import {
formatNumberPercentage,
t,
toBigNum,
getDateTimeFormat,
} from '@vegaprotocol/react-helpers';
import type { VegaValueFormatterParams } from '@vegaprotocol/ui-toolkit';
import type * as Schema from '@vegaprotocol/types';
@@ -296,6 +297,21 @@ export const MarketList = () => {
return value ? formatDistanceToNow(new Date(value)) : '-';
}}
/>
<AgGridColumn
headerName={t('Closing Time')}
field="proposal.terms.closingDatetime"
headerTooltip={t('Closing time of the market')}
valueFormatter={({
value,
}: VegaValueFormatterParams<
Market,
'proposal.terms.closingDatetime'
>) => {
return value
? getDateTimeFormat().format(new Date(value).getTime())
: '-';
}}
/>
</Grid>
<HealthDialog
@@ -1,5 +1,5 @@
import { useEnvironment } from '@vegaprotocol/environment';
import { useEthereumConfig } from '@vegaprotocol/web3';
import { getChainName, useEthereumConfig } from '@vegaprotocol/web3';
import { Button, Splash, AsyncRenderer } from '@vegaprotocol/ui-toolkit';
import { Web3ConnectDialog } from '@vegaprotocol/web3';
import { useWeb3React } from '@web3-react/core';
@@ -82,7 +82,7 @@ export const Web3Content = ({
<Splash>
<div className="flex flex-col items-center gap-12">
<p className="text-white">
This app only works on chain ID: {appChainId}
This app only works on {getChainName(appChainId)}
</p>
<Button onClick={() => connector.deactivate()}>Disconnect</Button>
</div>
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1,3 +1,3 @@
{
"hosts": ["https://api.n00.mainnet-mirror.vega.xyz/graphql"]
"hosts": ["https://api.n00.mainnet-mirror.vega.xyz/query"]
}
+8 -3
View File
@@ -21,7 +21,12 @@ The e2e tests run against a locally running instance of the Vega network, manage
- Install the required Vega smart contracts
- Set up DataNodes with a running GraphQL and REST APIs.
Refer to the [Vega Capsule readme](https://github.com/vegaprotocol/vegacapsule#readme) for setting up and running Capsule. You will need [Go 1.19 or later](https://go.dev/doc/install) and [Docker](https://docs.docker.com/get-docker/) installed.
1. Refer to the [Vega Capsule readme](https://github.com/vegaprotocol/vegacapsule#readme) for setting up and running Capsule - follow by Pre-start and Quick Start (points 1-2)
2. Bootstrap with auto-installed dependencies including wallet
```bash
vegacapsule network bootstrap --config-path=../frontend-monorepo/vegacapsule/config.hcl --force
```
### Troubleshooting
@@ -29,6 +34,6 @@ Refer to the [Vega Capsule readme](https://github.com/vegaprotocol/vegacapsule#r
## Vega Wallet Setup
Start by [downloading the Vega wallet software here](https://github.com/vegaprotocol/vega/releases).
You can then refer to (or run) `frontend-monorepo/vegacapsule/setup-vegawallet.sh`. This will initialise and configure your wallet to have the correct public keys and network config to run against capsule.
You can then refer to (or run) `vegacapsule/setup-vegawallet.sh`. This will initialise and configure your wallet to have the correct public keys and network config to run against capsule.
Go to the .env file in `apps/token-e2e` and set the `CYPRESS_VEGA_WALLET_API_TOKEN` environment variable by pasting in your wallets long lived api token
@@ -78,7 +78,7 @@
"timeWindow": "3600",
"scalingFactor": 10
},
"triggeringRatio": 0.7,
"triggeringRatio": "0.7",
"auctionExtension": "1"
},
"logNormal": {
@@ -728,7 +728,7 @@ context(
});
// 1005-PROP-009
it(
it.skip(
'Unable to vote on a freeform proposal - when some but not enough vega associated',
{ tags: '@smoke' },
function () {
+1
View File
@@ -8,3 +8,4 @@ NX_ETHERSCAN_URL=https://etherscan.io
NX_GITHUB_FEEDBACK_URL=https://github.com/vegaprotocol/feedback/discussions
NX_VEGA_EXPLORER_URL=https://explorer.vega.xyz
NX_VEGA_DOCS_URL=https://docs.vega.xyz/mainnet
NX_SENTRY_DSN=https://4b8c8a8ba07742648aa4dfe1b8d17e40:87edc2605e544f888305d7fc4a9141bd@o286262.ingest.sentry.io/5882996
+6 -6
View File
@@ -39,12 +39,12 @@ There are a few different configuration options offered for this app:
| **Flag** | **Purpose** |
| ----------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| `NX_APP_SENTRY_DSN` | The sentry endpoint to report to. Should be off in dev but set in live. |
| `NX_APP_VEGA_URL` | The GraphQL query endpoint of a [Vega data node](https://github.com/vegaprotocol/networks#data-node) |
| `NX_APP_DEX_STAKING_DISABLED` | Disable the dex liquidity page an show a coming soon message |
| `NX_APP_FAIRGROUND` | Change styling to be themed as the fairground version of the website |
| `NX_APP_INFURA_ID` | Infura fallback for if the user does not have a web3 compatible browser |
| `NX_APP_ENV` | Change network to connect to. When set to CUSTOM use CUSTOM\_\* vars for network parameters |
| `NX_SENTRY_DSN` | The sentry endpoint to report to. Should be off in dev but set in live. |
| `NX_VEGA_URL` | The GraphQL query endpoint of a [Vega data node](https://github.com/vegaprotocol/networks#data-node) |
| `NX_DEX_STAKING_DISABLED` | Disable the dex liquidity page an show a coming soon message |
| `NX_FAIRGROUND` | Change styling to be themed as the fairground version of the website |
| `NX_INFURA_ID` | Infura fallback for if the user does not have a web3 compatible browser |
| `NX_ENV` | Change network to connect to. |
| `NX_ETH_URL_CONNECT` (optional) | If set to true the below two must also be set. This allows siging transactions in brower to allow to connect to a local ganache node through cypress |
| `NX_ETH_WALLET_MNEMONIC` (optional) | The mnemonic to be used to sign transactions with in browser |
| `NX_LOCAL_PROVIDER_URL` (optional) | The local node to use to send transaction to when signing in browser |
@@ -1,5 +1,5 @@
import { Button, Splash } from '@vegaprotocol/ui-toolkit';
import { Web3ConnectDialog } from '@vegaprotocol/web3';
import { getChainName, Web3ConnectDialog } from '@vegaprotocol/web3';
import { useWeb3React } from '@web3-react/core';
import type { ReactElement } from 'react';
import { useCallback, useEffect } from 'react';
@@ -78,7 +78,7 @@ export const Web3Content = ({ children, appChainId }: Web3ContentProps) => {
<Splash>
<div className="flex flex-col items-center gap-12">
<p className="text-white">
This app only works on chain ID: {appChainId}
This app only works on {getChainName(appChainId)}
</p>
<Button onClick={() => connector.deactivate()}>Disconnect</Button>
</div>
+2 -2
View File
@@ -30,9 +30,9 @@ export function useAnimateValue(
) {
elRef.current?.animate(
[
{ backgroundColor: customColors.vega.red, color: colors.white },
{ backgroundColor: customColors.vega.pink, color: colors.white },
{
backgroundColor: customColors.vega.red,
backgroundColor: customColors.vega.pink,
color: colors.white,
offset: 0.8,
},
+5 -2
View File
@@ -159,8 +159,10 @@
"Tokens are held in different <trancheLink>Tranches</trancheLink>. Each tranche has its own schedule for how the tokens are unlocked.": "Tokens are held in different <trancheLink>Tranches</trancheLink>. Each tranche has its own schedule for how the tokens are unlocked.",
"proposals": "Proposals",
"proposal": "Proposal",
"submitting": "Submitting",
"submittingProposal": "Submitting proposal",
"submit": "Submit",
"submitProposal": "Submit proposal",
"connectWalletToSubmitProposal": "Connect your wallet to submit a proposal",
"proposedEnactment": "Proposed enactment",
"Enacted": "Enacted",
"enactedOn": "Enacted on",
@@ -729,5 +731,6 @@
"homeRewardsIntro": "Track rewards you've earned for trading, liquidity provision, market creation, and staking.",
"homeRewardsButtonText": "See rewards",
"homeVegaTokenIntro": "VEGA Token is a governance asset used to make and vote on proposals, and nominate validators.",
"homeVegaTokenButtonText": "Manage tokens"
"homeVegaTokenButtonText": "Manage tokens",
"downloadProposalJson": "Download proposal as JSON"
}
+26
View File
@@ -0,0 +1,26 @@
export const downloadJson = (jsonString: string, proposalTitle: string) => {
try {
const now = new Date();
const day = now.getDate().toString().padStart(2, '0');
const month = now.toLocaleString('en-US', { month: 'short' });
const year = now.getFullYear().toString();
const hours = now.getHours().toString().padStart(2, '0');
const minutes = now.getMinutes().toString().padStart(2, '0');
const seconds = now.getSeconds().toString().padStart(2, '0');
// e.g. "2023-Jan-03-23-59-59"
const formattedDateTime = `${day}-${month}-${year}-${hours}-${minutes}-${seconds}`;
const blob = new Blob([jsonString], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.style.display = 'none';
a.href = url;
a.download = `${proposalTitle}-${formattedDateTime}.json`;
document.body.appendChild(a);
a.click();
window.URL.revokeObjectURL(url);
document.body.removeChild(a);
} catch (error) {
console.log(error);
}
};
@@ -25,7 +25,7 @@ export const TargetAddressMismatch = ({
}}
components={{
bold: <strong />,
red: <span className={'text-vega-red'} />,
red: <span className={'text-vega-pink'} />,
}}
/>
</p>
@@ -5,3 +5,4 @@ export * from './proposal-form-terms';
export * from './proposal-form-submit';
export * from './proposal-form-transaction-dialog';
export * from './proposal-form-vote-and-enactment-deadline';
export * from './proposal-form-download-json';
@@ -0,0 +1,12 @@
import { fireEvent, render, screen } from '@testing-library/react';
import { ProposalFormDownloadJson } from './proposal-form-download-json';
describe('ProposalFormDownloadJson', () => {
it('calls the downloadJson method when the button is clicked', () => {
const downloadJson = jest.fn();
render(<ProposalFormDownloadJson downloadJson={downloadJson} />);
const button = screen.getByTestId('proposal-download-json');
fireEvent.click(button);
expect(downloadJson).toHaveBeenCalledTimes(1);
});
});
@@ -0,0 +1,19 @@
import { useTranslation } from 'react-i18next';
import { Button } from '@vegaprotocol/ui-toolkit';
interface ProposalFormDownloadJsonProps {
downloadJson: () => void;
}
export const ProposalFormDownloadJson = ({
downloadJson,
}: ProposalFormDownloadJsonProps) => {
const { t } = useTranslation();
return (
<div className="mb-6">
<Button data-testid="proposal-download-json" onClick={downloadJson}>
{t('downloadProposalJson')}
</Button>
</div>
);
};
@@ -0,0 +1,59 @@
import { render, screen } from '@testing-library/react';
import { VegaWalletContext } from '@vegaprotocol/wallet';
import { AppStateProvider } from '../../../../contexts/app-state/app-state-provider';
import { ProposalFormSubmit } from './proposal-form-submit';
import type { VegaWalletContextShape } from '@vegaprotocol/wallet';
const renderComponent = (
context: VegaWalletContextShape,
isSubmitting: boolean
) => {
render(
<AppStateProvider>
<VegaWalletContext.Provider value={context}>
<ProposalFormSubmit isSubmitting={isSubmitting} />
</VegaWalletContext.Provider>
</AppStateProvider>
);
};
describe('Proposal Form Submit', () => {
it('should display connection message and button if wallet not connected', () => {
renderComponent({ pubKey: null } as VegaWalletContextShape, false);
expect(
screen.getByText('Connect your wallet to submit a proposal')
).toBeInTheDocument();
expect(
screen.getByTestId('connect-to-vega-wallet-btn')
).toBeInTheDocument();
});
it('should display submit button if wallet is connected', () => {
const pubKey = { publicKey: '123456__123456', name: 'test' };
renderComponent(
{
pubKey: pubKey.publicKey,
pubKeys: [pubKey],
} as VegaWalletContextShape,
false
);
expect(screen.getByTestId('proposal-submit')).toHaveTextContent(
'Submit proposal'
);
});
it('should display submitting button text if wallet is connected and submitting', () => {
const pubKey = { publicKey: '123456__123456', name: 'test' };
renderComponent(
{
pubKey: pubKey.publicKey,
pubKeys: [pubKey],
} as VegaWalletContextShape,
true
);
expect(screen.getByTestId('proposal-submit')).toHaveTextContent(
'Submitting proposal'
);
});
});
@@ -1,5 +1,7 @@
import { useTranslation } from 'react-i18next';
import { Button } from '@vegaprotocol/ui-toolkit';
import { useVegaWallet } from '@vegaprotocol/wallet';
import { VegaWalletContainer } from '../../../../components/vega-wallet-container';
interface ProposalFormSubmitProps {
isSubmitting: boolean;
@@ -8,17 +10,25 @@ interface ProposalFormSubmitProps {
export const ProposalFormSubmit = ({
isSubmitting,
}: ProposalFormSubmitProps) => {
const { pubKey } = useVegaWallet();
const { t } = useTranslation();
return (
<div className="mt-10 my-20">
<Button
variant="primary"
type="submit"
data-testid="proposal-submit"
disabled={isSubmitting}
>
{isSubmitting ? t('Submitting') : t('Submit')} {t('Proposal')}
</Button>
<div className="mb-6">
<div className="mb-4 font-bold uppercase text-vega-orange">
{!pubKey && t('connectWalletToSubmitProposal')}
</div>
<VegaWalletContainer>
{() => (
<Button
variant="primary"
type="submit"
data-testid="proposal-submit"
disabled={isSubmitting}
>
{isSubmitting ? t('submittingProposal') : t('submitProposal')}
</Button>
)}
</VegaWalletContainer>
</div>
);
};
@@ -231,7 +231,7 @@ const EnactmentForm = ({
{deadlines.enactment && deadlines.enactment < deadlines.vote && (
<span
data-testid="enactment-before-voting-deadline"
className="block mt-4 text-vega-red-dark"
className="block mt-4 text-vega-pink"
>
{t('ProposalWillFailIfEnactmentIsEarlierThanVotingDeadline')}
</span>
@@ -437,7 +437,7 @@ export function ProposalFormVoteAndEnactmentDeadline({
const { t } = useTranslation();
return (
<>
<div className="mb-10">
<ProposalFormSubheader>
{enactmentRegister && enactmentMinClose && enactmentMaxClose
? t('ProposalVoteAndEnactmentTitle')
@@ -535,6 +535,6 @@ export function ProposalFormVoteAndEnactmentDeadline({
maxEnactmentHours={maxEnactmentHours}
/>
)}
</>
</div>
);
}
File diff suppressed because one or more lines are too long
@@ -109,6 +109,7 @@ describe('Propose Freeform', () => {
expect(screen.getByTestId('proposal-description')).toBeTruthy();
expect(screen.getByTestId('proposal-vote-deadline')).toBeTruthy();
expect(screen.getByTestId('proposal-submit')).toBeTruthy();
expect(screen.getByTestId('proposal-download-json')).toBeTruthy();
expect(screen.getByTestId('proposal-transaction-dialog')).toBeTruthy();
});
});
@@ -12,18 +12,19 @@ import {
ProposalFormSubmit,
ProposalFormTitle,
ProposalFormTransactionDialog,
ProposalFormDownloadJson,
ProposalFormVoteAndEnactmentDeadline,
} from '../../components/propose';
import { ProposalMinRequirements } from '../../components/shared';
import { AsyncRenderer, ExternalLink } from '@vegaprotocol/ui-toolkit';
import { Heading } from '../../../../components/heading';
import { VegaWalletContainer } from '../../../../components/vega-wallet-container';
import {
createDocsLinks,
NetworkParams,
useNetworkParams,
} from '@vegaprotocol/react-helpers';
import { ProposalUserAction } from '../../components/shared';
import { downloadJson } from '../../../../lib/download-json';
export interface FreeformProposalFormFields {
proposalVoteDeadline: string;
@@ -50,10 +51,11 @@ export const ProposeFreeform = () => {
handleSubmit,
formState: { isSubmitting, errors },
setValue,
watch,
} = useForm<FreeformProposalFormFields>();
const { finalizedProposal, submit, Dialog } = useProposalSubmit();
const onSubmit = async (fields: FreeformProposalFormFields) => {
const assembleProposal = (fields: FreeformProposalFormFields) => {
const isVoteDeadlineAtMinimum =
fields.proposalVoteDeadline ===
deadlineToRoundedHours(
@@ -66,7 +68,7 @@ export const ProposeFreeform = () => {
params.governance_proposal_freeform_maxClose
).toString();
await submit({
return {
rationale: {
title: fields.proposalTitle,
description: fields.proposalDescription,
@@ -79,86 +81,101 @@ export const ProposeFreeform = () => {
isVoteDeadlineAtMaximum
),
},
});
};
};
const onSubmit = async (fields: FreeformProposalFormFields) => {
await submit(assembleProposal(fields));
};
const viewJson = () => {
const formData = watch();
downloadJson(
JSON.stringify(assembleProposal(formData)),
'vega-freeform-proposal'
);
};
return (
<AsyncRenderer loading={loading} error={error} data={params}>
<Heading title={t('NewFreeformProposal')} />
<VegaWalletContainer>
{() => (
<>
<ProposalMinRequirements
minProposalBalance={
params.governance_proposal_freeform_minProposerBalance
}
spamProtectionMin={params.spam_protection_proposal_min_tokens}
userAction={ProposalUserAction.CREATE}
/>
<AsyncRenderer
loading={loading}
error={error}
data={params}
render={(params) => (
<>
<Heading title={t('NewFreeformProposal')} />
{VEGA_DOCS_URL && (
<p className="text-sm" data-testid="proposal-docs-link">
<span className="mr-1">{t('ProposalTermsText')}</span>
<ExternalLink
href={`${
createDocsLinks(VEGA_DOCS_URL).PROPOSALS_GUIDE
}${DOCS_LINK}`}
target="_blank"
>{`${
<ProposalMinRequirements
minProposalBalance={
params.governance_proposal_freeform_minProposerBalance
}
spamProtectionMin={params.spam_protection_proposal_min_tokens}
userAction={ProposalUserAction.CREATE}
/>
{VEGA_DOCS_URL && (
<p className="text-sm" data-testid="proposal-docs-link">
<span className="mr-1">{t('ProposalTermsText')}</span>
<ExternalLink
href={`${
createDocsLinks(VEGA_DOCS_URL).PROPOSALS_GUIDE
}${DOCS_LINK}`}</ExternalLink>
</p>
)}
}${DOCS_LINK}`}
target="_blank"
>{`${
createDocsLinks(VEGA_DOCS_URL).PROPOSALS_GUIDE
}${DOCS_LINK}`}</ExternalLink>
</p>
)}
{VEGA_EXPLORER_URL && (
<p className="text-sm">
{t('MoreProposalsInfo')}{' '}
<ExternalLink
href={`${VEGA_EXPLORER_URL}/governance`}
target="_blank"
>{`${VEGA_EXPLORER_URL}/governance`}</ExternalLink>
</p>
)}
{VEGA_EXPLORER_URL && (
<p className="text-sm">
{t('MoreProposalsInfo')}{' '}
<ExternalLink
href={`${VEGA_EXPLORER_URL}/governance`}
target="_blank"
>{`${VEGA_EXPLORER_URL}/governance`}</ExternalLink>
</p>
)}
<div data-testid="freeform-proposal-form">
<form onSubmit={handleSubmit(onSubmit)}>
<ProposalFormSubheader>
{t('ProposalRationale')}
</ProposalFormSubheader>
<div data-testid="freeform-proposal-form">
<form onSubmit={handleSubmit(onSubmit)}>
<ProposalFormSubheader>
{t('ProposalRationale')}
</ProposalFormSubheader>
<ProposalFormTitle
registerField={register('proposalTitle', {
required: t('Required'),
})}
errorMessage={errors?.proposalTitle?.message}
/>
<ProposalFormDescription
registerField={register('proposalDescription', {
required: t('Required'),
})}
errorMessage={errors?.proposalDescription?.message}
/>
<ProposalFormTitle
registerField={register('proposalTitle', {
required: t('Required'),
})}
errorMessage={errors?.proposalTitle?.message}
/>
<ProposalFormDescription
registerField={register('proposalDescription', {
required: t('Required'),
})}
errorMessage={errors?.proposalDescription?.message}
/>
<ProposalFormVoteAndEnactmentDeadline
onVoteMinMax={setValue}
voteRegister={register('proposalVoteDeadline', {
required: t('Required'),
})}
voteErrorMessage={errors?.proposalVoteDeadline?.message}
voteMinClose={params.governance_proposal_freeform_minClose}
voteMaxClose={params.governance_proposal_freeform_maxClose}
/>
<ProposalFormVoteAndEnactmentDeadline
onVoteMinMax={setValue}
voteRegister={register('proposalVoteDeadline', {
required: t('Required'),
})}
voteErrorMessage={errors?.proposalVoteDeadline?.message}
voteMinClose={params.governance_proposal_freeform_minClose}
voteMaxClose={params.governance_proposal_freeform_maxClose}
/>
<ProposalFormSubmit isSubmitting={isSubmitting} />
<ProposalFormTransactionDialog
finalizedProposal={finalizedProposal}
TransactionDialog={Dialog}
/>
</form>
</div>
</>
)}
</VegaWalletContainer>
</AsyncRenderer>
<ProposalFormSubmit isSubmitting={isSubmitting} />
<ProposalFormDownloadJson downloadJson={viewJson} />
<ProposalFormTransactionDialog
finalizedProposal={finalizedProposal}
TransactionDialog={Dialog}
/>
</form>
</div>
</>
)}
/>
);
};
@@ -112,6 +112,7 @@ describe('Propose Network Parameter', () => {
expect(screen.getByTestId('proposal-vote-deadline')).toBeTruthy();
expect(screen.getByTestId('proposal-enactment-deadline')).toBeTruthy();
expect(screen.getByTestId('proposal-submit')).toBeTruthy();
expect(screen.getByTestId('proposal-download-json')).toBeTruthy();
expect(screen.getByTestId('proposal-transaction-dialog')).toBeTruthy();
});
@@ -20,6 +20,7 @@ import {
ProposalFormTitle,
ProposalFormTransactionDialog,
ProposalFormVoteAndEnactmentDeadline,
ProposalFormDownloadJson,
} from '../../components/propose';
import { ProposalMinRequirements } from '../../components/shared';
import {
@@ -33,8 +34,8 @@ import {
TextArea,
} from '@vegaprotocol/ui-toolkit';
import { Heading } from '../../../../components/heading';
import { VegaWalletContainer } from '../../../../components/vega-wallet-container';
import { ProposalUserAction } from '../../components/shared';
import { downloadJson } from '../../../../lib/download-json';
interface SelectedNetworkParamCurrentValueProps {
value: string;
@@ -92,6 +93,7 @@ export const ProposeNetworkParameter = () => {
handleSubmit,
formState: { isSubmitting, errors },
setValue,
watch,
} = useForm<NetworkParameterProposalFormFields>();
const { finalizedProposal, submit, Dialog } = useProposalSubmit();
@@ -99,8 +101,8 @@ export const ProposeNetworkParameter = () => {
? Object.entries(params).find(([key]) => key === selectedNetworkParam)
: null;
const onSubmit = async (fields: NetworkParameterProposalFormFields) => {
const acutalNetworkParamKey = fields.proposalNetworkParameterKey
const assembleProposal = (fields: NetworkParameterProposalFormFields) => {
const actualNetworkParamKey = fields.proposalNetworkParameterKey
.split('_')
.join('.');
@@ -121,7 +123,7 @@ export const ProposeNetworkParameter = () => {
params.governance_proposal_updateNetParam_maxEnact
);
await submit({
return {
rationale: {
title: fields.proposalTitle,
description: fields.proposalDescription,
@@ -129,7 +131,7 @@ export const ProposeNetworkParameter = () => {
terms: {
updateNetworkParameter: {
changes: {
key: acutalNetworkParamKey,
key: actualNetworkParamKey,
value: fields.proposalNetworkParameterValue,
},
},
@@ -144,7 +146,19 @@ export const ProposeNetworkParameter = () => {
isEnactmentDeadlineAtMaximum
),
},
});
};
};
const onSubmit = async (fields: NetworkParameterProposalFormFields) => {
await submit(assembleProposal(fields));
};
const viewJson = () => {
const formData = watch();
downloadJson(
JSON.stringify(assembleProposal(formData)),
'vega-network-param-proposal'
);
};
return (
@@ -152,163 +166,161 @@ export const ProposeNetworkParameter = () => {
loading={networkParamsLoading}
error={networkParamsError}
data={params}
>
<Heading title={t('NetworkParameterProposal')} />
<VegaWalletContainer>
{() => (
<>
<ProposalMinRequirements
minProposalBalance={
params.governance_proposal_updateNetParam_minProposerBalance
}
spamProtectionMin={params.spam_protection_proposal_min_tokens}
userAction={ProposalUserAction.CREATE}
/>
render={(params) => (
<>
<Heading title={t('NetworkParameterProposal')} />
<ProposalMinRequirements
minProposalBalance={
params.governance_proposal_updateNetParam_minProposerBalance
}
spamProtectionMin={params.spam_protection_proposal_min_tokens}
userAction={ProposalUserAction.CREATE}
/>
{VEGA_DOCS_URL && (
<p className="text-sm" data-testid="proposal-docs-link">
<span className="mr-1">{t('ProposalTermsText')}</span>
<ExternalLink
href={`${
createDocsLinks(VEGA_DOCS_URL).PROPOSALS_GUIDE
}${DOCS_LINK}`}
target="_blank"
>{`${
{VEGA_DOCS_URL && (
<p className="text-sm" data-testid="proposal-docs-link">
<span className="mr-1">{t('ProposalTermsText')}</span>
<ExternalLink
href={`${
createDocsLinks(VEGA_DOCS_URL).PROPOSALS_GUIDE
}${DOCS_LINK}`}</ExternalLink>
</p>
)}
}${DOCS_LINK}`}
target="_blank"
>{`${
createDocsLinks(VEGA_DOCS_URL).PROPOSALS_GUIDE
}${DOCS_LINK}`}</ExternalLink>
</p>
)}
{VEGA_EXPLORER_URL && (
<p className="text-sm">
{t('MoreNetParamsInfo')}{' '}
<ExternalLink
href={`${VEGA_EXPLORER_URL}/network-parameters`}
target="_blank"
>{`${VEGA_EXPLORER_URL}/network-parameters`}</ExternalLink>
</p>
)}
{VEGA_EXPLORER_URL && (
<p className="text-sm">
{t('MoreNetParamsInfo')}{' '}
<ExternalLink
href={`${VEGA_EXPLORER_URL}/network-parameters`}
target="_blank"
>{`${VEGA_EXPLORER_URL}/network-parameters`}</ExternalLink>
</p>
)}
<div data-testid="network-parameter-proposal-form">
<form onSubmit={handleSubmit(onSubmit)}>
<ProposalFormSubheader>
{t('ProposalRationale')}
</ProposalFormSubheader>
<div data-testid="network-parameter-proposal-form">
<form onSubmit={handleSubmit(onSubmit)}>
<ProposalFormSubheader>
{t('ProposalRationale')}
</ProposalFormSubheader>
<ProposalFormTitle
registerField={register('proposalTitle', {
<ProposalFormTitle
registerField={register('proposalTitle', {
required: t('Required'),
})}
errorMessage={errors?.proposalTitle?.message}
/>
<ProposalFormDescription
registerField={register('proposalDescription', {
required: t('Required'),
})}
errorMessage={errors?.proposalDescription?.message}
/>
<ProposalFormSubheader>
{t('SelectAParameterToChange')}
</ProposalFormSubheader>
<FormGroup
label={t('SelectAParameterToChange')}
labelFor="proposal-parameter-key"
hideLabel={true}
>
<Select
data-testid="proposal-parameter-select"
id="proposal-parameter-key"
{...register('proposalNetworkParameterKey', {
required: t('Required'),
})}
errorMessage={errors?.proposalTitle?.message}
/>
<ProposalFormDescription
registerField={register('proposalDescription', {
required: t('Required'),
})}
errorMessage={errors?.proposalDescription?.message}
/>
<ProposalFormSubheader>
{t('SelectAParameterToChange')}
</ProposalFormSubheader>
<FormGroup
label={t('SelectAParameterToChange')}
labelFor="proposal-parameter-key"
hideLabel={true}
onChange={(e) => setSelectedNetworkParam(e.target.value)}
value={selectedNetworkParam}
>
<Select
data-testid="proposal-parameter-select"
id="proposal-parameter-key"
{...register('proposalNetworkParameterKey', {
required: t('Required'),
})}
onChange={(e) => setSelectedNetworkParam(e.target.value)}
value={selectedNetworkParam}
>
<option value="">{t('SelectParameter')}</option>
{Object.keys(params).map((key) => {
const actualKey = key.split('_').join('.');
return (
<option key={key} value={key}>
{actualKey}
</option>
);
})}
</Select>
{errors?.proposalNetworkParameterKey?.message && (
<InputError intent="danger">
{errors?.proposalNetworkParameterKey?.message}
</InputError>
)}
</FormGroup>
{selectedNetworkParam && (
<div className="mt-[-10px]">
{selectedParamEntry && (
<SelectedNetworkParamCurrentValue
value={selectedParamEntry[1]}
/>
)}
<FormGroup
label={t('NewProposedValue')}
labelFor="proposal-parameter-new-value"
>
<TextArea
data-testid="selected-proposal-param-new-value"
id="proposal-parameter-new-value"
{...register('proposalNetworkParameterValue', {
required: t('Required'),
})}
/>
{errors?.proposalNetworkParameterValue?.message && (
<InputError intent="danger">
{errors?.proposalNetworkParameterValue?.message}
</InputError>
)}
</FormGroup>
</div>
<option value="">{t('SelectParameter')}</option>
{Object.keys(params).map((key) => {
const actualKey = key.split('_').join('.');
return (
<option key={key} value={key}>
{actualKey}
</option>
);
})}
</Select>
{errors?.proposalNetworkParameterKey?.message && (
<InputError intent="danger">
{errors?.proposalNetworkParameterKey?.message}
</InputError>
)}
</FormGroup>
<ProposalFormVoteAndEnactmentDeadline
onVoteMinMax={setValue}
voteRegister={register('proposalVoteDeadline', {
required: t('Required'),
})}
voteErrorMessage={errors?.proposalVoteDeadline?.message}
voteMinClose={
params.governance_proposal_updateNetParam_minClose
}
voteMaxClose={
params.governance_proposal_updateNetParam_maxClose
}
onEnactMinMax={setValue}
enactmentRegister={register('proposalEnactmentDeadline', {
required: t('Required'),
})}
enactmentErrorMessage={
errors?.proposalEnactmentDeadline?.message
}
enactmentMinClose={
params.governance_proposal_updateNetParam_minEnact
}
enactmentMaxClose={
params.governance_proposal_updateNetParam_maxEnact
}
/>
{selectedNetworkParam && (
<div className="mt-[-10px]">
{selectedParamEntry && (
<SelectedNetworkParamCurrentValue
value={selectedParamEntry[1]}
/>
)}
<ProposalFormSubmit isSubmitting={isSubmitting} />
<ProposalFormTransactionDialog
finalizedProposal={finalizedProposal}
TransactionDialog={Dialog}
/>
</form>
</div>
</>
)}
</VegaWalletContainer>
</AsyncRenderer>
<FormGroup
label={t('NewProposedValue')}
labelFor="proposal-parameter-new-value"
>
<TextArea
data-testid="selected-proposal-param-new-value"
id="proposal-parameter-new-value"
{...register('proposalNetworkParameterValue', {
required: t('Required'),
})}
/>
{errors?.proposalNetworkParameterValue?.message && (
<InputError intent="danger">
{errors?.proposalNetworkParameterValue?.message}
</InputError>
)}
</FormGroup>
</div>
)}
<ProposalFormVoteAndEnactmentDeadline
onVoteMinMax={setValue}
voteRegister={register('proposalVoteDeadline', {
required: t('Required'),
})}
voteErrorMessage={errors?.proposalVoteDeadline?.message}
voteMinClose={
params.governance_proposal_updateNetParam_minClose
}
voteMaxClose={
params.governance_proposal_updateNetParam_maxClose
}
onEnactMinMax={setValue}
enactmentRegister={register('proposalEnactmentDeadline', {
required: t('Required'),
})}
enactmentErrorMessage={
errors?.proposalEnactmentDeadline?.message
}
enactmentMinClose={
params.governance_proposal_updateNetParam_minEnact
}
enactmentMaxClose={
params.governance_proposal_updateNetParam_maxEnact
}
/>
<ProposalFormSubmit isSubmitting={isSubmitting} />
<ProposalFormDownloadJson downloadJson={viewJson} />
<ProposalFormTransactionDialog
finalizedProposal={finalizedProposal}
TransactionDialog={Dialog}
/>
</form>
</div>
</>
)}
/>
);
};
@@ -110,6 +110,7 @@ describe('Propose New Asset', () => {
expect(screen.getByTestId('proposal-validation-deadline')).toBeTruthy();
expect(screen.getByTestId('proposal-enactment-deadline')).toBeTruthy();
expect(screen.getByTestId('proposal-submit')).toBeTruthy();
expect(screen.getByTestId('proposal-download-json')).toBeTruthy();
expect(screen.getByTestId('proposal-transaction-dialog')).toBeTruthy();
});
});
@@ -21,13 +21,14 @@ import {
ProposalFormTerms,
ProposalFormTitle,
ProposalFormTransactionDialog,
ProposalFormDownloadJson,
ProposalFormVoteAndEnactmentDeadline,
} from '../../components/propose';
import { ProposalMinRequirements } from '../../components/shared';
import { AsyncRenderer, ExternalLink } from '@vegaprotocol/ui-toolkit';
import { Heading } from '../../../../components/heading';
import { VegaWalletContainer } from '../../../../components/vega-wallet-container';
import { ProposalUserAction } from '../../components/shared';
import { downloadJson } from '../../../../lib/download-json';
export interface NewAssetProposalFormFields {
proposalVoteDeadline: string;
@@ -62,10 +63,11 @@ export const ProposeNewAsset = () => {
handleSubmit,
formState: { isSubmitting, errors },
setValue,
watch,
} = useForm<NewAssetProposalFormFields>();
const { finalizedProposal, submit, Dialog } = useProposalSubmit();
const onSubmit = async (fields: NewAssetProposalFormFields) => {
const assembleProposal = (fields: NewAssetProposalFormFields) => {
const isVoteDeadlineAtMinimum = doesValueEquateToParam(
fields.proposalVoteDeadline,
params.governance_proposal_asset_minClose
@@ -87,7 +89,7 @@ export const ProposeNewAsset = () => {
params.governance_proposal_asset_maxClose
);
await submit({
return {
rationale: {
title: fields.proposalTitle,
description: fields.proposalDescription,
@@ -111,7 +113,19 @@ export const ProposeNewAsset = () => {
isValidationDeadlineAtMaximum
),
},
});
};
};
const onSubmit = async (fields: NewAssetProposalFormFields) => {
await submit(assembleProposal(fields));
};
const viewJson = () => {
const formData = watch();
downloadJson(
JSON.stringify(assembleProposal(formData)),
'vega-new-asset-proposal'
);
};
return (
@@ -119,112 +133,111 @@ export const ProposeNewAsset = () => {
loading={networkParamsLoading}
error={networkParamsError}
data={params}
>
<Heading title={t('NewAssetProposal')} />
<VegaWalletContainer>
{() => (
<>
<ProposalMinRequirements
minProposalBalance={
params.governance_proposal_asset_minProposerBalance
}
spamProtectionMin={params.spam_protection_proposal_min_tokens}
userAction={ProposalUserAction.CREATE}
/>
render={(params) => (
<>
<Heading title={t('NewAssetProposal')} />
{VEGA_DOCS_URL && (
<p className="text-sm" data-testid="proposal-docs-link">
<span className="mr-1">{t('ProposalTermsText')}</span>
<ExternalLink
href={`${
createDocsLinks(VEGA_DOCS_URL).PROPOSALS_GUIDE
}${DOCS_LINK}`}
target="_blank"
>{`${
<ProposalMinRequirements
minProposalBalance={
params.governance_proposal_asset_minProposerBalance
}
spamProtectionMin={params.spam_protection_proposal_min_tokens}
userAction={ProposalUserAction.CREATE}
/>
{VEGA_DOCS_URL && (
<p className="text-sm" data-testid="proposal-docs-link">
<span className="mr-1">{t('ProposalTermsText')}</span>
<ExternalLink
href={`${
createDocsLinks(VEGA_DOCS_URL).PROPOSALS_GUIDE
}${DOCS_LINK}`}</ExternalLink>
</p>
)}
}${DOCS_LINK}`}
target="_blank"
>{`${
createDocsLinks(VEGA_DOCS_URL).PROPOSALS_GUIDE
}${DOCS_LINK}`}</ExternalLink>
</p>
)}
{VEGA_EXPLORER_URL && (
<p className="text-sm">
{t('MoreAssetsInfo')}{' '}
<ExternalLink
href={`${VEGA_EXPLORER_URL}/assets`}
target="_blank"
>{`${VEGA_EXPLORER_URL}/assets`}</ExternalLink>
</p>
)}
{VEGA_EXPLORER_URL && (
<p className="text-sm">
{t('MoreAssetsInfo')}{' '}
<ExternalLink
href={`${VEGA_EXPLORER_URL}/assets`}
target="_blank"
>{`${VEGA_EXPLORER_URL}/assets`}</ExternalLink>
</p>
)}
<div data-testid="new-asset-proposal-form">
<form onSubmit={handleSubmit(onSubmit)}>
<ProposalFormSubheader>
{t('ProposalRationale')}
</ProposalFormSubheader>
<div data-testid="new-asset-proposal-form">
<form onSubmit={handleSubmit(onSubmit)}>
<ProposalFormSubheader>
{t('ProposalRationale')}
</ProposalFormSubheader>
<ProposalFormTitle
registerField={register('proposalTitle', {
required: t('Required'),
})}
errorMessage={errors?.proposalTitle?.message}
/>
<ProposalFormTitle
registerField={register('proposalTitle', {
required: t('Required'),
})}
errorMessage={errors?.proposalTitle?.message}
/>
<ProposalFormDescription
registerField={register('proposalDescription', {
required: t('Required'),
})}
errorMessage={errors?.proposalDescription?.message}
/>
<ProposalFormDescription
registerField={register('proposalDescription', {
required: t('Required'),
})}
errorMessage={errors?.proposalDescription?.message}
/>
<ProposalFormSubheader>{t('NewAsset')}</ProposalFormSubheader>
<ProposalFormSubheader>{t('NewAsset')}</ProposalFormSubheader>
<ProposalFormTerms
registerField={register('proposalTerms', {
required: t('Required'),
validate: (value) => validateJson(value),
})}
labelOverride={'Terms.newAsset (JSON format)'}
errorMessage={errors?.proposalTerms?.message}
docsLink={DOCS_LINK}
/>
<ProposalFormTerms
registerField={register('proposalTerms', {
required: t('Required'),
validate: (value) => validateJson(value),
})}
labelOverride={'Terms.newAsset (JSON format)'}
errorMessage={errors?.proposalTerms?.message}
docsLink={DOCS_LINK}
/>
<ProposalFormVoteAndEnactmentDeadline
onVoteMinMax={setValue}
voteRegister={register('proposalVoteDeadline', {
required: t('Required'),
})}
voteErrorMessage={errors?.proposalVoteDeadline?.message}
voteMinClose={params.governance_proposal_asset_minClose}
voteMaxClose={params.governance_proposal_asset_maxClose}
onEnactMinMax={setValue}
enactmentRegister={register('proposalEnactmentDeadline', {
required: t('Required'),
})}
enactmentErrorMessage={
errors?.proposalEnactmentDeadline?.message
}
enactmentMinClose={params.governance_proposal_asset_minEnact}
enactmentMaxClose={params.governance_proposal_asset_maxEnact}
validationRequired={true}
onValidationMinMax={setValue}
validationRegister={register('proposalValidationDeadline', {
required: t('Required'),
})}
validationErrorMessage={
errors?.proposalValidationDeadline?.message
}
/>
<ProposalFormVoteAndEnactmentDeadline
onVoteMinMax={setValue}
voteRegister={register('proposalVoteDeadline', {
required: t('Required'),
})}
voteErrorMessage={errors?.proposalVoteDeadline?.message}
voteMinClose={params.governance_proposal_asset_minClose}
voteMaxClose={params.governance_proposal_asset_maxClose}
onEnactMinMax={setValue}
enactmentRegister={register('proposalEnactmentDeadline', {
required: t('Required'),
})}
enactmentErrorMessage={
errors?.proposalEnactmentDeadline?.message
}
enactmentMinClose={params.governance_proposal_asset_minEnact}
enactmentMaxClose={params.governance_proposal_asset_maxEnact}
validationRequired={true}
onValidationMinMax={setValue}
validationRegister={register('proposalValidationDeadline', {
required: t('Required'),
})}
validationErrorMessage={
errors?.proposalValidationDeadline?.message
}
/>
<ProposalFormSubmit isSubmitting={isSubmitting} />
<ProposalFormTransactionDialog
finalizedProposal={finalizedProposal}
TransactionDialog={Dialog}
/>
</form>
</div>
</>
)}
</VegaWalletContainer>
</AsyncRenderer>
<ProposalFormSubmit isSubmitting={isSubmitting} />
<ProposalFormDownloadJson downloadJson={viewJson} />
<ProposalFormTransactionDialog
finalizedProposal={finalizedProposal}
TransactionDialog={Dialog}
/>
</form>
</div>
</>
)}
/>
);
};
@@ -104,6 +104,7 @@ describe('Propose New Market', () => {
expect(screen.getByTestId('proposal-vote-deadline')).toBeTruthy();
expect(screen.getByTestId('proposal-enactment-deadline')).toBeTruthy();
expect(screen.getByTestId('proposal-submit')).toBeTruthy();
expect(screen.getByTestId('proposal-download-json')).toBeTruthy();
expect(screen.getByTestId('proposal-transaction-dialog')).toBeTruthy();
});
});
@@ -20,13 +20,14 @@ import {
ProposalFormTerms,
ProposalFormTitle,
ProposalFormTransactionDialog,
ProposalFormDownloadJson,
ProposalFormVoteAndEnactmentDeadline,
} from '../../components/propose';
import { ProposalMinRequirements } from '../../components/shared';
import { AsyncRenderer, ExternalLink } from '@vegaprotocol/ui-toolkit';
import { Heading } from '../../../../components/heading';
import { VegaWalletContainer } from '../../../../components/vega-wallet-container';
import { ProposalUserAction } from '../../components/shared';
import { downloadJson } from '../../../../lib/download-json';
export interface NewMarketProposalFormFields {
proposalVoteDeadline: string;
@@ -60,10 +61,11 @@ export const ProposeNewMarket = () => {
handleSubmit,
formState: { isSubmitting, errors },
setValue,
watch,
} = useForm<NewMarketProposalFormFields>();
const { finalizedProposal, submit, Dialog } = useProposalSubmit();
const onSubmit = async (fields: NewMarketProposalFormFields) => {
const assembleProposal = (fields: NewMarketProposalFormFields) => {
const isVoteDeadlineAtMinimum = doesValueEquateToParam(
fields.proposalVoteDeadline,
params.governance_proposal_market_minClose
@@ -81,7 +83,7 @@ export const ProposeNewMarket = () => {
params.governance_proposal_market_maxEnact
);
await submit({
return {
rationale: {
title: fields.proposalTitle,
description: fields.proposalDescription,
@@ -101,7 +103,19 @@ export const ProposeNewMarket = () => {
isEnactmentDeadlineAtMaximum
),
},
});
};
};
const onSubmit = async (fields: NewMarketProposalFormFields) => {
await submit(assembleProposal(fields));
};
const viewJson = () => {
const formData = watch();
downloadJson(
JSON.stringify(assembleProposal(formData)),
'vega-new-market-proposal'
);
};
return (
@@ -109,104 +123,103 @@ export const ProposeNewMarket = () => {
loading={networkParamsLoading}
error={networkParamsError}
data={params}
>
<Heading title={t('NewMarketProposal')} />
<VegaWalletContainer>
{() => (
<>
<ProposalMinRequirements
minProposalBalance={
params.governance_proposal_market_minProposerBalance
}
spamProtectionMin={params.spam_protection_proposal_min_tokens}
userAction={ProposalUserAction.CREATE}
/>
render={(params) => (
<>
<Heading title={t('NewMarketProposal')} />
{VEGA_DOCS_URL && (
<p className="text-sm" data-testid="proposal-docs-link">
<span className="mr-1">{t('ProposalTermsText')}</span>
<ExternalLink
href={`${
createDocsLinks(VEGA_DOCS_URL).PROPOSALS_GUIDE
}${DOCS_LINK}`}
target="_blank"
>{`${
<ProposalMinRequirements
minProposalBalance={
params.governance_proposal_market_minProposerBalance
}
spamProtectionMin={params.spam_protection_proposal_min_tokens}
userAction={ProposalUserAction.CREATE}
/>
{VEGA_DOCS_URL && (
<p className="text-sm" data-testid="proposal-docs-link">
<span className="mr-1">{t('ProposalTermsText')}</span>
<ExternalLink
href={`${
createDocsLinks(VEGA_DOCS_URL).PROPOSALS_GUIDE
}${DOCS_LINK}`}</ExternalLink>
</p>
)}
}${DOCS_LINK}`}
target="_blank"
>{`${
createDocsLinks(VEGA_DOCS_URL).PROPOSALS_GUIDE
}${DOCS_LINK}`}</ExternalLink>
</p>
)}
{VEGA_EXPLORER_URL && (
<p className="text-sm">
{t('MoreMarketsInfo')}{' '}
<ExternalLink
href={`${VEGA_EXPLORER_URL}/markets`}
target="_blank"
>{`${VEGA_EXPLORER_URL}/markets`}</ExternalLink>
</p>
)}
{VEGA_EXPLORER_URL && (
<p className="text-sm">
{t('MoreMarketsInfo')}{' '}
<ExternalLink
href={`${VEGA_EXPLORER_URL}/markets`}
target="_blank"
>{`${VEGA_EXPLORER_URL}/markets`}</ExternalLink>
</p>
)}
<div data-testid="new-market-proposal-form">
<form onSubmit={handleSubmit(onSubmit)}>
<ProposalFormSubheader>
{t('ProposalRationale')}
</ProposalFormSubheader>
<div data-testid="new-market-proposal-form">
<form onSubmit={handleSubmit(onSubmit)}>
<ProposalFormSubheader>
{t('ProposalRationale')}
</ProposalFormSubheader>
<ProposalFormTitle
registerField={register('proposalTitle', {
required: t('Required'),
})}
errorMessage={errors?.proposalTitle?.message}
/>
<ProposalFormTitle
registerField={register('proposalTitle', {
required: t('Required'),
})}
errorMessage={errors?.proposalTitle?.message}
/>
<ProposalFormDescription
registerField={register('proposalDescription', {
required: t('Required'),
})}
errorMessage={errors?.proposalDescription?.message}
/>
<ProposalFormDescription
registerField={register('proposalDescription', {
required: t('Required'),
})}
errorMessage={errors?.proposalDescription?.message}
/>
<ProposalFormSubheader>{t('NewMarket')}</ProposalFormSubheader>
<ProposalFormSubheader>{t('NewMarket')}</ProposalFormSubheader>
<ProposalFormTerms
registerField={register('proposalTerms', {
required: t('Required'),
validate: (value) => validateJson(value),
})}
labelOverride={'Terms.newMarket (JSON format)'}
errorMessage={errors?.proposalTerms?.message}
docsLink={DOCS_LINK}
/>
<ProposalFormTerms
registerField={register('proposalTerms', {
required: t('Required'),
validate: (value) => validateJson(value),
})}
labelOverride={'Terms.newMarket (JSON format)'}
errorMessage={errors?.proposalTerms?.message}
docsLink={DOCS_LINK}
/>
<ProposalFormVoteAndEnactmentDeadline
onVoteMinMax={setValue}
voteRegister={register('proposalVoteDeadline', {
required: t('Required'),
})}
voteErrorMessage={errors?.proposalVoteDeadline?.message}
voteMinClose={params.governance_proposal_market_minClose}
voteMaxClose={params.governance_proposal_market_maxClose}
onEnactMinMax={setValue}
enactmentRegister={register('proposalEnactmentDeadline', {
required: t('Required'),
})}
enactmentErrorMessage={
errors?.proposalEnactmentDeadline?.message
}
enactmentMinClose={params.governance_proposal_market_minEnact}
enactmentMaxClose={params.governance_proposal_market_maxEnact}
/>
<ProposalFormVoteAndEnactmentDeadline
onVoteMinMax={setValue}
voteRegister={register('proposalVoteDeadline', {
required: t('Required'),
})}
voteErrorMessage={errors?.proposalVoteDeadline?.message}
voteMinClose={params.governance_proposal_market_minClose}
voteMaxClose={params.governance_proposal_market_maxClose}
onEnactMinMax={setValue}
enactmentRegister={register('proposalEnactmentDeadline', {
required: t('Required'),
})}
enactmentErrorMessage={
errors?.proposalEnactmentDeadline?.message
}
enactmentMinClose={params.governance_proposal_market_minEnact}
enactmentMaxClose={params.governance_proposal_market_maxEnact}
/>
<ProposalFormSubmit isSubmitting={isSubmitting} />
<ProposalFormTransactionDialog
finalizedProposal={finalizedProposal}
TransactionDialog={Dialog}
/>
</form>
</div>
</>
)}
</VegaWalletContainer>
</AsyncRenderer>
<ProposalFormSubmit isSubmitting={isSubmitting} />
<ProposalFormDownloadJson downloadJson={viewJson} />
<ProposalFormTransactionDialog
finalizedProposal={finalizedProposal}
TransactionDialog={Dialog}
/>
</form>
</div>
</>
)}
/>
);
};
@@ -2,7 +2,6 @@ import { useForm } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
import { useEnvironment } from '@vegaprotocol/environment';
import { Heading } from '../../../../components/heading';
import { VegaWalletContainer } from '../../../../components/vega-wallet-container';
import {
AsyncRenderer,
ExternalLink,
@@ -20,8 +19,10 @@ import { useProposalSubmit } from '@vegaprotocol/governance';
import {
ProposalFormSubmit,
ProposalFormTransactionDialog,
ProposalFormDownloadJson,
} from '../../components/propose';
import { ProposalRawMinRequirements } from './proposal-raw-min-requirements';
import { downloadJson } from '../../../../lib/download-json';
export interface RawProposalFormFields {
rawProposalData: string;
@@ -48,6 +49,7 @@ export const ProposeRaw = () => {
register,
handleSubmit,
formState: { isSubmitting, errors },
watch,
} = useForm<RawProposalFormFields>();
const { finalizedProposal, submit, Dialog } = useProposalSubmit();
@@ -57,88 +59,90 @@ export const ProposeRaw = () => {
await submit(JSON.parse(fields.rawProposalData));
};
const viewJson = () => {
const formData = watch();
downloadJson(JSON.stringify(formData), 'vega-raw-proposal');
};
return (
<AsyncRenderer
loading={networkParamsLoading}
error={networkParamsError}
data={params}
>
<Heading title={t('NewRawProposal')} />
<VegaWalletContainer>
{() => (
<>
<ProposalRawMinRequirements
assetMin={params.governance_proposal_asset_minProposerBalance}
updateAssetMin={
params.governance_proposal_updateAsset_minProposerBalance
}
marketMin={params.governance_proposal_market_minProposerBalance}
updateMarketMin={
params.governance_proposal_updateMarket_minProposerBalance
}
updateNetParamMin={
params.governance_proposal_updateNetParam_minProposerBalance
}
freeformMin={
params.governance_proposal_freeform_minProposerBalance
}
spamProtectionMin={params.spam_protection_proposal_min_tokens}
/>
render={(params) => (
<>
<Heading title={t('NewRawProposal')} />
{VEGA_DOCS_URL && (
<p className="text-sm" data-testid="proposal-docs-link">
<span className="mr-1">{t('ProposalTermsText')}</span>
<ExternalLink
href={createDocsLinks(VEGA_DOCS_URL).PROPOSALS_GUIDE}
target="_blank"
>
{createDocsLinks(VEGA_DOCS_URL).PROPOSALS_GUIDE}
</ExternalLink>
</p>
)}
<ProposalRawMinRequirements
assetMin={params.governance_proposal_asset_minProposerBalance}
updateAssetMin={
params.governance_proposal_updateAsset_minProposerBalance
}
marketMin={params.governance_proposal_market_minProposerBalance}
updateMarketMin={
params.governance_proposal_updateMarket_minProposerBalance
}
updateNetParamMin={
params.governance_proposal_updateNetParam_minProposerBalance
}
freeformMin={params.governance_proposal_freeform_minProposerBalance}
spamProtectionMin={params.spam_protection_proposal_min_tokens}
/>
{VEGA_EXPLORER_URL && (
<p className="text-sm">
{t('MoreProposalsInfo')}{' '}
<ExternalLink
href={`${VEGA_EXPLORER_URL}/governance`}
target="_blank"
>{`${VEGA_EXPLORER_URL}/governance`}</ExternalLink>
</p>
)}
{VEGA_DOCS_URL && (
<p className="text-sm" data-testid="proposal-docs-link">
<span className="mr-1">{t('ProposalTermsText')}</span>
<ExternalLink
href={createDocsLinks(VEGA_DOCS_URL).PROPOSALS_GUIDE}
target="_blank"
>
{createDocsLinks(VEGA_DOCS_URL).PROPOSALS_GUIDE}
</ExternalLink>
</p>
)}
<div data-testid="raw-proposal-form">
<form onSubmit={handleSubmit(onSubmit)}>
<FormGroup
label="Make a proposal by submitting JSON"
labelFor="proposal-data"
>
<TextArea
id="proposal-data"
className="min-h-[200px]"
hasError={hasError}
data-testid="proposal-data"
{...register('rawProposalData', {
required: t('Required'),
validate: (value) => validateJson(value),
})}
/>
{errors.rawProposalData?.message && (
<InputError intent="danger">
{errors.rawProposalData?.message}
</InputError>
)}
</FormGroup>
<ProposalFormSubmit isSubmitting={isSubmitting} />
<ProposalFormTransactionDialog
finalizedProposal={finalizedProposal}
TransactionDialog={Dialog}
{VEGA_EXPLORER_URL && (
<p className="text-sm">
{t('MoreProposalsInfo')}{' '}
<ExternalLink
href={`${VEGA_EXPLORER_URL}/governance`}
target="_blank"
>{`${VEGA_EXPLORER_URL}/governance`}</ExternalLink>
</p>
)}
<div data-testid="raw-proposal-form">
<form onSubmit={handleSubmit(onSubmit)}>
<FormGroup
label="Make a proposal by submitting JSON"
labelFor="proposal-data"
>
<TextArea
id="proposal-data"
className="min-h-[200px]"
hasError={hasError}
data-testid="proposal-data"
{...register('rawProposalData', {
required: t('Required'),
validate: (value) => validateJson(value),
})}
/>
</form>
</div>
</>
)}
</VegaWalletContainer>
</AsyncRenderer>
{errors.rawProposalData?.message && (
<InputError intent="danger">
{errors.rawProposalData?.message}
</InputError>
)}
</FormGroup>
<ProposalFormSubmit isSubmitting={isSubmitting} />
<ProposalFormDownloadJson downloadJson={viewJson} />
<ProposalFormTransactionDialog
finalizedProposal={finalizedProposal}
TransactionDialog={Dialog}
/>
</form>
</div>
</>
)}
/>
);
};
@@ -111,6 +111,7 @@ describe('Propose Update Asset', () => {
expect(screen.getByTestId('proposal-vote-deadline')).toBeTruthy();
expect(screen.getByTestId('proposal-enactment-deadline')).toBeTruthy();
expect(screen.getByTestId('proposal-submit')).toBeTruthy();
expect(screen.getByTestId('proposal-download-json')).toBeTruthy();
expect(screen.getByTestId('proposal-transaction-dialog')).toBeTruthy();
});
});
@@ -20,13 +20,14 @@ import {
ProposalFormTerms,
ProposalFormTitle,
ProposalFormTransactionDialog,
ProposalFormDownloadJson,
ProposalFormVoteAndEnactmentDeadline,
} from '../../components/propose';
import { ProposalMinRequirements } from '../../components/shared';
import { AsyncRenderer, ExternalLink } from '@vegaprotocol/ui-toolkit';
import { Heading } from '../../../../components/heading';
import { VegaWalletContainer } from '../../../../components/vega-wallet-container';
import { ProposalUserAction } from '../../components/shared';
import { downloadJson } from '../../../../lib/download-json';
export interface UpdateAssetProposalFormFields {
proposalVoteDeadline: string;
@@ -60,10 +61,11 @@ export const ProposeUpdateAsset = () => {
handleSubmit,
formState: { isSubmitting, errors },
setValue,
watch,
} = useForm<UpdateAssetProposalFormFields>();
const { finalizedProposal, submit, Dialog } = useProposalSubmit();
const onSubmit = async (fields: UpdateAssetProposalFormFields) => {
const assembleProposal = (fields: UpdateAssetProposalFormFields) => {
const isVoteDeadlineAtMinimum = doesValueEquateToParam(
fields.proposalVoteDeadline,
params.governance_proposal_updateAsset_minClose
@@ -81,7 +83,7 @@ export const ProposeUpdateAsset = () => {
params.governance_proposal_updateAsset_maxEnact
);
await submit({
return {
rationale: {
title: fields.proposalTitle,
description: fields.proposalDescription,
@@ -101,7 +103,19 @@ export const ProposeUpdateAsset = () => {
isEnactmentDeadlineAtMaximum
),
},
});
};
};
const onSubmit = async (fields: UpdateAssetProposalFormFields) => {
await submit(assembleProposal(fields));
};
const viewJson = () => {
const formData = watch();
downloadJson(
JSON.stringify(assembleProposal(formData)),
'vega-update-asset-proposal'
);
};
return (
@@ -109,110 +123,107 @@ export const ProposeUpdateAsset = () => {
loading={networkParamsLoading}
error={networkParamsError}
data={params}
>
<Heading title={t('UpdateAssetProposal')} />
<VegaWalletContainer>
{() => (
<>
<ProposalMinRequirements
minProposalBalance={
params.governance_proposal_updateAsset_minProposerBalance
}
spamProtectionMin={params.spam_protection_proposal_min_tokens}
userAction={ProposalUserAction.CREATE}
/>
render={(params) => (
<>
<Heading title={t('UpdateAssetProposal')} />
{VEGA_DOCS_URL && (
<p className="text-sm" data-testid="proposal-docs-link">
<span className="mr-1">{t('ProposalTermsText')}</span>
<ExternalLink
href={`${
createDocsLinks(VEGA_DOCS_URL).PROPOSALS_GUIDE
}${DOCS_LINK}`}
target="_blank"
>{`${
<ProposalMinRequirements
minProposalBalance={
params.governance_proposal_updateAsset_minProposerBalance
}
spamProtectionMin={params.spam_protection_proposal_min_tokens}
userAction={ProposalUserAction.CREATE}
/>
{VEGA_DOCS_URL && (
<p className="text-sm" data-testid="proposal-docs-link">
<span className="mr-1">{t('ProposalTermsText')}</span>
<ExternalLink
href={`${
createDocsLinks(VEGA_DOCS_URL).PROPOSALS_GUIDE
}${DOCS_LINK}`}</ExternalLink>
</p>
)}
}${DOCS_LINK}`}
target="_blank"
>{`${
createDocsLinks(VEGA_DOCS_URL).PROPOSALS_GUIDE
}${DOCS_LINK}`}</ExternalLink>
</p>
)}
{VEGA_EXPLORER_URL && (
<p className="text-sm">
{t('MoreAssetsInfo')}{' '}
<ExternalLink
href={`${VEGA_EXPLORER_URL}/assets`}
target="_blank"
>{`${VEGA_EXPLORER_URL}/assets`}</ExternalLink>
</p>
)}
{VEGA_EXPLORER_URL && (
<p className="text-sm">
{t('MoreAssetsInfo')}{' '}
<ExternalLink
href={`${VEGA_EXPLORER_URL}/assets`}
target="_blank"
>{`${VEGA_EXPLORER_URL}/assets`}</ExternalLink>
</p>
)}
<div data-testid="update-asset-proposal-form">
<form onSubmit={handleSubmit(onSubmit)}>
<ProposalFormSubheader>
{t('ProposalRationale')}
</ProposalFormSubheader>
<div data-testid="update-asset-proposal-form">
<form onSubmit={handleSubmit(onSubmit)}>
<ProposalFormSubheader>
{t('ProposalRationale')}
</ProposalFormSubheader>
<ProposalFormTitle
registerField={register('proposalTitle', {
required: t('Required'),
})}
errorMessage={errors?.proposalTitle?.message}
/>
<ProposalFormTitle
registerField={register('proposalTitle', {
required: t('Required'),
})}
errorMessage={errors?.proposalTitle?.message}
/>
<ProposalFormDescription
registerField={register('proposalDescription', {
required: t('Required'),
})}
errorMessage={errors?.proposalDescription?.message}
/>
<ProposalFormDescription
registerField={register('proposalDescription', {
required: t('Required'),
})}
errorMessage={errors?.proposalDescription?.message}
/>
<ProposalFormSubheader>
{t('UpdateAsset')}
</ProposalFormSubheader>
<ProposalFormSubheader>{t('UpdateAsset')}</ProposalFormSubheader>
<ProposalFormTerms
registerField={register('proposalTerms', {
required: t('Required'),
validate: (value) => validateJson(value),
})}
labelOverride={'Terms.updateAsset (JSON format)'}
errorMessage={errors?.proposalTerms?.message}
docsLink={DOCS_LINK}
/>
<ProposalFormTerms
registerField={register('proposalTerms', {
required: t('Required'),
validate: (value) => validateJson(value),
})}
labelOverride={'Terms.updateAsset (JSON format)'}
errorMessage={errors?.proposalTerms?.message}
docsLink={DOCS_LINK}
/>
<ProposalFormVoteAndEnactmentDeadline
onVoteMinMax={setValue}
voteRegister={register('proposalVoteDeadline', {
required: t('Required'),
})}
voteErrorMessage={errors?.proposalVoteDeadline?.message}
voteMinClose={params.governance_proposal_updateAsset_minClose}
voteMaxClose={params.governance_proposal_updateAsset_maxClose}
onEnactMinMax={setValue}
enactmentRegister={register('proposalEnactmentDeadline', {
required: t('Required'),
})}
enactmentErrorMessage={
errors?.proposalEnactmentDeadline?.message
}
enactmentMinClose={
params.governance_proposal_updateAsset_minEnact
}
enactmentMaxClose={
params.governance_proposal_updateAsset_maxEnact
}
/>
<ProposalFormVoteAndEnactmentDeadline
onVoteMinMax={setValue}
voteRegister={register('proposalVoteDeadline', {
required: t('Required'),
})}
voteErrorMessage={errors?.proposalVoteDeadline?.message}
voteMinClose={params.governance_proposal_updateAsset_minClose}
voteMaxClose={params.governance_proposal_updateAsset_maxClose}
onEnactMinMax={setValue}
enactmentRegister={register('proposalEnactmentDeadline', {
required: t('Required'),
})}
enactmentErrorMessage={
errors?.proposalEnactmentDeadline?.message
}
enactmentMinClose={
params.governance_proposal_updateAsset_minEnact
}
enactmentMaxClose={
params.governance_proposal_updateAsset_maxEnact
}
/>
<ProposalFormSubmit isSubmitting={isSubmitting} />
<ProposalFormTransactionDialog
finalizedProposal={finalizedProposal}
TransactionDialog={Dialog}
/>
</form>
</div>
</>
)}
</VegaWalletContainer>
</AsyncRenderer>
<ProposalFormSubmit isSubmitting={isSubmitting} />
<ProposalFormDownloadJson downloadJson={viewJson} />
<ProposalFormTransactionDialog
finalizedProposal={finalizedProposal}
TransactionDialog={Dialog}
/>
</form>
</div>
</>
)}
/>
);
};
@@ -187,6 +187,7 @@ describe('Propose Update Market', () => {
expect(screen.getByTestId('proposal-vote-deadline')).toBeTruthy();
expect(screen.getByTestId('proposal-enactment-deadline')).toBeTruthy();
expect(screen.getByTestId('proposal-submit')).toBeTruthy();
expect(screen.getByTestId('proposal-download-json')).toBeTruthy();
expect(screen.getByTestId('proposal-transaction-dialog')).toBeTruthy();
});
@@ -21,6 +21,7 @@ import {
ProposalFormTerms,
ProposalFormTitle,
ProposalFormTransactionDialog,
ProposalFormDownloadJson,
ProposalFormVoteAndEnactmentDeadline,
} from '../../components/propose';
import { ProposalMinRequirements } from '../../components/shared';
@@ -34,9 +35,9 @@ import {
Select,
} from '@vegaprotocol/ui-toolkit';
import { Heading } from '../../../../components/heading';
import { VegaWalletContainer } from '../../../../components/vega-wallet-container';
import { ProposalUserAction } from '../../components/shared';
import { useProposalMarketsQueryQuery } from './__generated___/UpdateMarket';
import { downloadJson } from '../../../../lib/download-json';
export interface UpdateMarketProposalFormFields {
proposalVoteDeadline: string;
@@ -101,10 +102,11 @@ export const ProposeUpdateMarket = () => {
handleSubmit,
formState: { isSubmitting, errors },
setValue,
watch,
} = useForm<UpdateMarketProposalFormFields>();
const { finalizedProposal, submit, Dialog } = useProposalSubmit();
const onSubmit = async (fields: UpdateMarketProposalFormFields) => {
const assembleProposal = (fields: UpdateMarketProposalFormFields) => {
const isVoteDeadlineAtMinimum = doesValueEquateToParam(
fields.proposalVoteDeadline,
params.governance_proposal_updateMarket_minClose
@@ -122,7 +124,7 @@ export const ProposeUpdateMarket = () => {
params.governance_proposal_updateMarket_maxEnact
);
await submit({
return {
rationale: {
title: fields.proposalTitle,
description: fields.proposalDescription,
@@ -145,176 +147,182 @@ export const ProposeUpdateMarket = () => {
isEnactmentDeadlineAtMaximum
),
},
});
};
};
const onSubmit = async (fields: UpdateMarketProposalFormFields) => {
await submit(assembleProposal(fields));
};
const viewJson = () => {
const formData = watch();
downloadJson(
JSON.stringify(assembleProposal(formData)),
'vega-update-market-proposal'
);
};
return (
<AsyncRenderer
loading={networkParamsLoading && marketsLoading}
error={networkParamsError && marketsError}
data={params && marketsData}
>
<Heading title={t('UpdateMarketProposal')} />
<VegaWalletContainer>
{() => (
<>
<ProposalMinRequirements
minProposalBalance={
params.governance_proposal_updateMarket_minProposerBalance
}
spamProtectionMin={params.spam_protection_proposal_min_tokens}
userAction={ProposalUserAction.CREATE}
/>
data={{ ...params, ...marketsData }}
render={(data) => (
<>
<Heading title={t('UpdateMarketProposal')} />
<ProposalMinRequirements
minProposalBalance={
data.governance_proposal_updateMarket_minProposerBalance
}
spamProtectionMin={data.spam_protection_proposal_min_tokens}
userAction={ProposalUserAction.CREATE}
/>
{VEGA_DOCS_URL && (
<p className="text-sm" data-testid="proposal-docs-link">
<span className="mr-1">{t('ProposalTermsText')}</span>
<ExternalLink
href={`${
createDocsLinks(VEGA_DOCS_URL).PROPOSALS_GUIDE
}${DOCS_LINK}`}
target="_blank"
>{`${
{VEGA_DOCS_URL && (
<p className="text-sm" data-testid="proposal-docs-link">
<span className="mr-1">{t('ProposalTermsText')}</span>
<ExternalLink
href={`${
createDocsLinks(VEGA_DOCS_URL).PROPOSALS_GUIDE
}${DOCS_LINK}`}</ExternalLink>
</p>
)}
}${DOCS_LINK}`}
target="_blank"
>{`${
createDocsLinks(VEGA_DOCS_URL).PROPOSALS_GUIDE
}${DOCS_LINK}`}</ExternalLink>
</p>
)}
{VEGA_EXPLORER_URL && (
<p className="text-sm">
{t('MoreMarketsInfo')}{' '}
<ExternalLink
href={`${VEGA_EXPLORER_URL}/markets`}
target="_blank"
>{`${VEGA_EXPLORER_URL}/markets`}</ExternalLink>
</p>
)}
{VEGA_EXPLORER_URL && (
<p className="text-sm">
{t('MoreMarketsInfo')}{' '}
<ExternalLink
href={`${VEGA_EXPLORER_URL}/markets`}
target="_blank"
>{`${VEGA_EXPLORER_URL}/markets`}</ExternalLink>
</p>
)}
<div data-testid="update-market-proposal-form">
<form onSubmit={handleSubmit(onSubmit)}>
<ProposalFormSubheader>
{t('ProposalRationale')}
</ProposalFormSubheader>
<div data-testid="update-market-proposal-form">
<form onSubmit={handleSubmit(onSubmit)}>
<ProposalFormSubheader>
{t('ProposalRationale')}
</ProposalFormSubheader>
<ProposalFormTitle
registerField={register('proposalTitle', {
<ProposalFormTitle
registerField={register('proposalTitle', {
required: t('Required'),
})}
errorMessage={errors?.proposalTitle?.message}
/>
<ProposalFormDescription
registerField={register('proposalDescription', {
required: t('Required'),
})}
errorMessage={errors?.proposalDescription?.message}
/>
<ProposalFormSubheader>
{t('SelectAMarketToChange')}
</ProposalFormSubheader>
<FormGroup
label={t('SelectAMarketToChange')}
labelFor="proposal-market"
hideLabel={true}
>
<Select
data-testid="proposal-market-select"
id="proposal-market"
{...register('proposalMarketId', {
required: t('Required'),
})}
errorMessage={errors?.proposalTitle?.message}
/>
<ProposalFormDescription
registerField={register('proposalDescription', {
required: t('Required'),
})}
errorMessage={errors?.proposalDescription?.message}
/>
<ProposalFormSubheader>
{t('SelectAMarketToChange')}
</ProposalFormSubheader>
<FormGroup
label={t('SelectAMarketToChange')}
labelFor="proposal-market"
hideLabel={true}
onChange={(e) => setSelectedMarket(e.target.value)}
>
<Select
data-testid="proposal-market-select"
id="proposal-market"
{...register('proposalMarketId', {
required: t('Required'),
})}
onChange={(e) => setSelectedMarket(e.target.value)}
>
<option value="">{t('SelectMarket')}</option>
{sortedMarkets.map((market) => (
<option value={market.id} key={market.id}>
{market.tradableInstrument.instrument.name}
</option>
))}
</Select>
{errors?.proposalMarketId?.message && (
<InputError intent="danger">
{errors?.proposalMarketId?.message}
</InputError>
)}
</FormGroup>
{selectedMarket && (
<div className="mt-[-20px] mb-6">
<KeyValueTable data-testid="update-market-details">
<KeyValueTableRow>
{t('MarketName')}
{
marketsData?.marketsConnection?.edges?.find(
({ node: market }) => market.id === selectedMarket
)?.node.tradableInstrument.instrument.name
}
</KeyValueTableRow>
<KeyValueTableRow>
{t('MarketCode')}
{
marketsData?.marketsConnection?.edges?.find(
({ node: market }) => market.id === selectedMarket
)?.node.tradableInstrument.instrument.code
}
</KeyValueTableRow>
<KeyValueTableRow>
{t('MarketId')}
{selectedMarket}
</KeyValueTableRow>
</KeyValueTable>
</div>
<option value="">{t('SelectMarket')}</option>
{sortedMarkets.map((market) => (
<option value={market.id} key={market.id}>
{market.tradableInstrument.instrument.name}
</option>
))}
</Select>
{errors?.proposalMarketId?.message && (
<InputError intent="danger">
{errors?.proposalMarketId?.message}
</InputError>
)}
</FormGroup>
<ProposalFormTerms
registerField={register('proposalTerms', {
required: t('Required'),
validate: (value) => validateJson(value),
})}
labelOverride={t('ProposeUpdateMarketTerms')}
errorMessage={errors?.proposalTerms?.message}
docsLink={DOCS_LINK}
/>
{selectedMarket && (
<div className="mt-[-20px] mb-6">
<KeyValueTable data-testid="update-market-details">
<KeyValueTableRow>
{t('MarketName')}
{
data.marketsConnection?.edges?.find(
({ node: market }) => market.id === selectedMarket
)?.node.tradableInstrument.instrument.name
}
</KeyValueTableRow>
<KeyValueTableRow>
{t('MarketCode')}
{
data.marketsConnection?.edges?.find(
({ node: market }) => market.id === selectedMarket
)?.node.tradableInstrument.instrument.code
}
</KeyValueTableRow>
<KeyValueTableRow>
{t('MarketId')}
{selectedMarket}
</KeyValueTableRow>
</KeyValueTable>
</div>
)}
<ProposalFormVoteAndEnactmentDeadline
onVoteMinMax={setValue}
voteRegister={register('proposalVoteDeadline', {
required: t('Required'),
})}
voteErrorMessage={errors?.proposalVoteDeadline?.message}
voteMinClose={
params.governance_proposal_updateMarket_minClose
}
voteMaxClose={
params.governance_proposal_updateMarket_maxClose
}
onEnactMinMax={setValue}
enactmentRegister={register('proposalEnactmentDeadline', {
required: t('Required'),
})}
enactmentErrorMessage={
errors?.proposalEnactmentDeadline?.message
}
enactmentMinClose={
params.governance_proposal_updateMarket_minEnact
}
enactmentMaxClose={
params.governance_proposal_updateMarket_maxEnact
}
/>
<ProposalFormTerms
registerField={register('proposalTerms', {
required: t('Required'),
validate: (value) => validateJson(value),
})}
labelOverride={t('ProposeUpdateMarketTerms')}
errorMessage={errors?.proposalTerms?.message}
docsLink={DOCS_LINK}
/>
<ProposalFormSubmit isSubmitting={isSubmitting} />
<ProposalFormTransactionDialog
finalizedProposal={finalizedProposal}
TransactionDialog={Dialog}
/>
</form>
</div>
</>
)}
</VegaWalletContainer>
</AsyncRenderer>
<ProposalFormVoteAndEnactmentDeadline
onVoteMinMax={setValue}
voteRegister={register('proposalVoteDeadline', {
required: t('Required'),
})}
voteErrorMessage={errors?.proposalVoteDeadline?.message}
voteMinClose={data.governance_proposal_updateMarket_minClose}
voteMaxClose={data.governance_proposal_updateMarket_maxClose}
onEnactMinMax={setValue}
enactmentRegister={register('proposalEnactmentDeadline', {
required: t('Required'),
})}
enactmentErrorMessage={
errors?.proposalEnactmentDeadline?.message
}
enactmentMinClose={
data.governance_proposal_updateMarket_minEnact
}
enactmentMaxClose={
data.governance_proposal_updateMarket_maxEnact
}
/>
<ProposalFormSubmit isSubmitting={isSubmitting} />
<ProposalFormDownloadJson downloadJson={viewJson} />
<ProposalFormTransactionDialog
finalizedProposal={finalizedProposal}
TransactionDialog={Dialog}
/>
</form>
</div>
</>
)}
/>
);
};
@@ -169,7 +169,7 @@ export const DisassociatePage = ({
)}
</p>
<p data-testid="disassociation-warning">
<span className="text-vega-red">{t('Warning')}:</span>{' '}
<span className="text-vega-pink">{t('Warning')}:</span>{' '}
{t(
'Any tokens that have been nominated to a node will sacrifice rewards they are due for the current epoch. If you do not wish to sacrifice these, you should remove stake from a node at the end of an epoch before disassociation.'
)}
+1 -1
View File
@@ -96,7 +96,7 @@ export const StakingNode = ({ data, previousEpochData }: StakingNodeProps) => {
if (!nodeInfo) {
return (
<span data-testid="staking-node-not-found" className={'text-vega-red'}>
<span data-testid="staking-node-not-found" className={'text-vega-pink'}>
{t('stakingNodeNotFound', { node })}
</span>
);
@@ -192,7 +192,7 @@ export const StakingForm = ({
availableStakeToRemove.isEqualTo(0) && (
<div className="mb-4">
{lien.isGreaterThan(0) ? (
<span className="text-vega-red">
<span className="text-vega-pink">
{t('stakeNodeWrongVegaKey')}
</span>
) : (
+14 -14
View File
@@ -6,43 +6,41 @@ const amountField = 'input[name="amount"]';
const formFieldError = 'input-error-text';
describe('deposit form validation', { tags: '@smoke' }, () => {
beforeEach(() => {
before(() => {
cy.mockWeb3Provider();
cy.mockSubscription();
cy.mockTradingPage();
cy.setVegaWallet();
cy.visit('/#/portfolio');
cy.get('main[data-testid="/portfolio"]').should('exist');
cy.getByTestId('Deposits').click();
cy.getByTestId('tab-deposits').contains('Connect your Vega wallet');
cy.connectVegaWallet();
cy.getByTestId('deposit-button').click();
cy.wait('@Assets');
connectEthereumWallet();
cy.getByTestId('deposit-submit').click();
});
it('handles empty fields', () => {
cy.getByTestId(formFieldError).should('contain.text', 'Required');
cy.getByTestId(formFieldError).should('have.length', 2);
});
it('unable to select assets not enabled', () => {
connectEthereumWallet();
cy.getByTestId('deposit-submit').click();
// Assets not enabled in mocks
cy.get(assetSelectField + ' option:contains(Asset 2)').should('not.exist');
cy.get(assetSelectField + ' option:contains(Asset 3)').should('not.exist');
cy.get(assetSelectField + ' option:contains(Asset 4)').should('not.exist');
});
it('handles empty fields', () => {
connectEthereumWallet();
// Submit form to trigger any empty validation messages
cy.getByTestId('deposit-submit').click();
cy.getByTestId(formFieldError).should('contain.text', 'Required');
cy.getByTestId(formFieldError).should('have.length', 2);
// Invalid public key
it('invalid public key', () => {
cy.get(toAddressField)
.clear()
.type('INVALID_DEPOSIT_TO_ADDRESS')
.next(`[data-testid="${formFieldError}"]`)
.should('have.text', 'Invalid Vega key');
});
it('invalid amount', () => {
// Deposit amount smaller than minimum viable for selected asset
// Select an amount so that we have a known decimal places value to work with
cy.get(assetSelectField).select('Euro');
@@ -51,7 +49,9 @@ describe('deposit form validation', { tags: '@smoke' }, () => {
.type('0.00000000000000000000000000000000001')
.next(`[data-testid="${formFieldError}"]`)
.should('have.text', 'Value is below minimum');
});
it('insufficient funds', () => {
// Deposit amount is valid, but less than approved. This will always be the case because our
// CI wallet wont have approved any assets
cy.get(amountField)
@@ -37,7 +37,7 @@ describe('vega wallet v1', { tags: '@smoke' }, () => {
cy.getByTestId(form).find('#wallet').click().type('invalid name');
cy.getByTestId(form).find('#passphrase').click().type('invalid password');
cy.getByTestId('rest-connector-form').find('button[type=submit]').click();
cy.getByTestId('form-error').should('have.text', 'Invalid credentials');
cy.getByTestId('form-error').should('have.text', 'No wallet detected');
});
it('doesnt connect with invalid fields', () => {
@@ -133,6 +133,7 @@ describe('Navbar', { tags: '@smoke' }, () => {
cy.mockTradingPage();
cy.mockSubscription();
cy.visit('/');
cy.wait('@Market');
cy.getByTestId('dialog-close').click();
});
@@ -224,4 +224,34 @@ describe('home', { tags: '@regression' }, () => {
.should('exist');
});
});
describe('redirect should take last visited market into consideration', () => {
beforeEach(() => {
cy.window().then((window) => {
window.localStorage.removeItem('marketId');
});
});
it('marketId comes from existing market', () => {
cy.window().then((window) => {
window.localStorage.setItem('marketId', 'market-1');
cy.visit('/');
cy.wait('@Market');
cy.location('hash').should('equal', '#/markets/market-1');
cy.get('[role="dialog"]').should('not.exist');
});
});
it('marketId comes from not-existing market', () => {
cy.window().then((window) => {
window.localStorage.setItem('marketId', 'market-not-existing');
cy.mockGQL((req) => {
aliasGQLQuery(req, 'Market', null);
});
cy.visit('/');
cy.wait('@Market');
cy.location('hash').should('equal', '#/markets/market-not-existing');
cy.get('[role="dialog"]').should('not.exist');
});
});
});
});
@@ -235,9 +235,9 @@ describe('market states not accepting orders', { tags: '@smoke' }, function () {
beforeEach(function () {
cy.mockTradingPage(marketState);
cy.mockSubscription();
cy.setVegaWallet();
cy.visit('/#/markets/market-0');
cy.wait('@Market');
cy.connectVegaWallet();
});
it('must display that market is not accepting orders', function () {
cy.getByTestId('place-order').click();
@@ -2,6 +2,7 @@ beforeEach(() => {
cy.mockTradingPage();
cy.mockWeb3Provider();
cy.mockSubscription();
cy.setVegaWallet();
cy.visit('/#/markets/market-0');
});
@@ -10,8 +11,6 @@ describe('accounts', { tags: '@smoke' }, () => {
const tradingAccountRowId = '[row-id="asset-0"]';
cy.getByTestId('Collateral').click();
cy.connectVegaWallet();
cy.getByTestId('tab-accounts').should('be.visible');
cy.getByTestId('tab-accounts')
@@ -30,11 +30,11 @@ const displayTomorrow = () => {
describe('time in force default values', () => {
before(() => {
cy.setVegaWallet();
cy.mockTradingPage();
cy.mockSubscription();
cy.visit('/#/markets/market-0');
cy.wait('@Market');
cy.connectVegaWallet();
});
it('must have market order set up to IOC by default', function () {
@@ -59,20 +59,15 @@ describe('time in force default values', () => {
describe('must submit order', { tags: '@smoke' }, () => {
// 7002-SORD-039
before(() => {
cy.setVegaWallet();
cy.mockTradingPage();
cy.mockSubscription();
cy.visit('/#/markets/market-0');
cy.wait('@Market');
cy.connectVegaWallet();
cy.window().then(function (window) {
cy.wrap(window.localStorage.getItem('vega_wallet_config')).as('cfg');
});
});
beforeEach(() => {
cy.window().then(function (window) {
window.localStorage.setItem('vega_wallet_config', this.cfg);
});
cy.setVegaWallet();
});
it('successfully places market buy order', () => {
@@ -158,6 +153,7 @@ describe(
{ tags: '@regression' },
() => {
before(() => {
cy.setVegaWallet();
cy.mockTradingPage(
Schema.MarketState.STATE_SUSPENDED,
Schema.MarketTradingMode.TRADING_MODE_BATCH_AUCTION,
@@ -166,16 +162,10 @@ describe(
cy.mockSubscription();
cy.visit('/#/markets/market-0');
cy.wait('@Market');
cy.connectVegaWallet();
cy.window().then(function (window) {
cy.wrap(window.localStorage.getItem('vega_wallet_config')).as('cfg');
});
});
beforeEach(() => {
cy.window().then(function (window) {
window.localStorage.setItem('vega_wallet_config', this.cfg);
});
cy.setVegaWallet();
});
it('successfully places limit buy order', () => {
@@ -232,6 +222,7 @@ describe(
{ tags: '@regression' },
() => {
before(() => {
cy.setVegaWallet();
cy.mockTradingPage(
Schema.MarketState.STATE_SUSPENDED,
Schema.MarketTradingMode.TRADING_MODE_OPENING_AUCTION,
@@ -240,16 +231,10 @@ describe(
cy.mockSubscription();
cy.visit('/#/markets/market-0');
cy.wait('@Market');
cy.connectVegaWallet();
cy.window().then(function (window) {
cy.wrap(window.localStorage.getItem('vega_wallet_config')).as('cfg');
});
});
beforeEach(() => {
cy.window().then(function (window) {
window.localStorage.setItem('vega_wallet_config', this.cfg);
});
cy.setVegaWallet();
});
it('successfully places limit buy order', () => {
@@ -306,6 +291,7 @@ describe(
{ tags: '@regression' },
() => {
before(() => {
cy.setVegaWallet();
cy.mockTradingPage(
Schema.MarketState.STATE_SUSPENDED,
Schema.MarketTradingMode.TRADING_MODE_MONITORING_AUCTION,
@@ -314,16 +300,10 @@ describe(
cy.mockSubscription();
cy.visit('/#/markets/market-0');
cy.wait('@Market');
cy.connectVegaWallet();
cy.window().then(function (window) {
cy.wrap(window.localStorage.getItem('vega_wallet_config')).as('cfg');
});
});
beforeEach(() => {
cy.window().then(function (window) {
window.localStorage.setItem('vega_wallet_config', this.cfg);
});
cy.setVegaWallet();
});
it('successfully places limit buy order', () => {
@@ -421,10 +401,10 @@ describe('deal ticket validation', { tags: '@smoke' }, () => {
describe('deal ticket size validation', { tags: '@smoke' }, function () {
beforeEach(() => {
cy.setVegaWallet();
cy.mockTradingPage();
cy.visit('/#/markets/market-0');
cy.wait('@Market');
cy.connectVegaWallet();
});
it('must warn if order size input has too many digits after the decimal place', function () {
@@ -455,14 +435,18 @@ describe('deal ticket size validation', { tags: '@smoke' }, function () {
describe('limit order validations', { tags: '@smoke' }, () => {
before(() => {
cy.setVegaWallet();
cy.mockTradingPage();
cy.mockSubscription();
cy.visit('/#/markets/market-0');
cy.connectVegaWallet();
cy.wait('@Market');
cy.getByTestId(toggleLimit).click();
});
beforeEach(() => {
cy.setVegaWallet();
});
it('must see the price unit', function () {
//7002-SORD-018
cy.getByTestId(orderPriceField)
@@ -544,11 +528,17 @@ describe('limit order validations', { tags: '@smoke' }, () => {
describe('market order validations', { tags: '@smoke' }, () => {
before(() => {
cy.setVegaWallet();
cy.mockTradingPage();
cy.visit('/#/markets/market-0');
cy.wait('@Market');
cy.getByTestId(toggleMarket).click();
});
beforeEach(() => {
cy.setVegaWallet();
});
it('must not see the price unit', function () {
//7002-SORD-019
cy.getByTestId(orderPriceField).should('not.exist');
@@ -587,6 +577,7 @@ describe('market order validations', { tags: '@smoke' }, () => {
describe('suspended market validation', { tags: '@regression' }, () => {
before(() => {
cy.setVegaWallet();
cy.mockTradingPage(
Schema.MarketState.STATE_SUSPENDED,
Schema.MarketTradingMode.TRADING_MODE_MONITORING_AUCTION,
@@ -595,7 +586,10 @@ describe('suspended market validation', { tags: '@regression' }, () => {
cy.mockSubscription();
cy.visit('/#/markets/market-0');
cy.wait('@Market');
cy.connectVegaWallet();
});
beforeEach(() => {
cy.setVegaWallet();
});
it('should show warning for market order', function () {
@@ -608,6 +602,7 @@ describe('suspended market validation', { tags: '@regression' }, () => {
'This market is in auction until it reaches sufficient liquidity. Only limit orders are permitted when market is in auction'
);
});
it('should show info for allowed TIF', function () {
cy.getByTestId(toggleLimit).click();
cy.getByTestId(orderPriceField).clear().type('0.1');
@@ -635,6 +630,7 @@ describe('suspended market validation', { tags: '@regression' }, () => {
describe('account validation', { tags: '@regression' }, () => {
describe('zero balance error', () => {
beforeEach(() => {
cy.setVegaWallet();
cy.mockTradingPage();
cy.mockGQL((req) => {
aliasGQLQuery(
@@ -663,7 +659,6 @@ describe('account validation', { tags: '@regression' }, () => {
});
cy.mockSubscription();
cy.visit('/#/markets/market-0');
cy.connectVegaWallet();
cy.wait('@Market');
});
@@ -682,6 +677,7 @@ describe('account validation', { tags: '@regression' }, () => {
describe('not enough balance warning', () => {
beforeEach(() => {
cy.setVegaWallet();
cy.mockTradingPage();
cy.mockGQL((req) => {
aliasGQLQuery(
@@ -699,9 +695,9 @@ describe('account validation', { tags: '@regression' }, () => {
});
cy.mockSubscription();
cy.visit('/#/markets/market-0');
cy.connectVegaWallet();
cy.wait('@Market');
});
it('should display info and button for deposit', () => {
//7002-SORD-003
// warning should show immediately
@@ -12,6 +12,7 @@ describe('fills', { tags: '@regression' }, () => {
)
);
});
cy.setVegaWallet();
cy.mockTradingPage();
cy.mockGQL((req) => {
aliasGQLQuery(
@@ -27,20 +28,12 @@ describe('fills', { tags: '@regression' }, () => {
cy.visit('/#/portfolio');
cy.get('main[data-testid="/portfolio"]').should('exist');
cy.getByTestId('Fills').click();
cy.getByTestId('tab-fills').contains('Connect your Vega wallet');
cy.connectVegaWallet();
validateFillsDisplayed();
});
it('renders fills on trading tab', () => {
cy.mockTradingPage();
cy.visit('/#/markets/market-0');
cy.getByTestId('Fills').click();
cy.getByTestId('tab-fills').should(
'contain.text',
'Connect your Vega wallet'
);
cy.connectVegaWallet();
validateFillsDisplayed();
});
@@ -27,11 +27,11 @@ describe('orders list', { tags: '@smoke' }, () => {
cy.spy(subscriptionMocks, 'OrdersUpdate');
cy.mockTradingPage();
cy.mockSubscription(subscriptionMocks);
cy.setVegaWallet();
cy.visit('/#/markets/market-0');
cy.getByTestId('Orders').click();
cy.connectVegaWallet();
cy.wait('@Orders').then(() => {
expect(subscriptionMocks.OrdersUpdate).to.be.calledOnce;
expect(subscriptionMocks.OrdersUpdate).to.be.calledTwice;
});
cy.wait('@Markets');
});
@@ -125,11 +125,11 @@ describe('subscribe orders', { tags: '@smoke' }, () => {
cy.spy(subscriptionMocks, 'OrdersUpdate');
cy.mockTradingPage();
cy.mockSubscription(subscriptionMocks);
cy.setVegaWallet();
cy.visit('/#/markets/market-0');
cy.getByTestId('Orders').click();
cy.connectVegaWallet();
cy.wait('@Orders').then(() => {
expect(subscriptionMocks.OrdersUpdate).to.be.calledOnce;
expect(subscriptionMocks.OrdersUpdate).to.be.calledTwice;
});
});
const orderId = '1234567890';
@@ -216,12 +216,14 @@ describe('subscribe orders', { tags: '@smoke' }, () => {
it('must see a parked order', () => {
// 7002-SORD-048
// NOT COVERED: must see an explanation of why parked orders happen
updateOrder({
id: orderId,
status: Schema.OrderStatus.STATUS_PARKED,
});
cy.getByTestId(`order-status-${orderId}`).should('have.text', 'Parked');
cy.getByTestId(`order-status-${orderId}`).should(
'have.text',
'Parked: Internal error'
);
});
it('must see the size of the order and direction/side -', () => {
@@ -341,11 +343,11 @@ describe('amend and cancel order', { tags: '@smoke' }, () => {
cy.spy(subscriptionMocks, 'OrdersUpdate');
cy.mockTradingPage();
cy.mockSubscription(subscriptionMocks);
cy.setVegaWallet();
cy.visit('/#/markets/market-0');
cy.getByTestId('Orders').click();
cy.connectVegaWallet();
cy.wait('@Orders').then(() => {
expect(subscriptionMocks.OrdersUpdate).to.be.calledOnce;
expect(subscriptionMocks.OrdersUpdate).to.be.calledTwice;
});
cy.mockVegaWalletTransaction();
});
@@ -423,4 +425,30 @@ describe('amend and cancel order', { tags: '@smoke' }, () => {
testOrderCancellation(order);
});
});
it('must be warned (pre-submit) if the input price has too many digits after the decimal place for the market', () => {
// 7003-MORD-016
updateOrder({
id: orderId,
status: Schema.OrderStatus.STATUS_ACTIVE,
peggedOrder: null,
liquidityProvisionId: null,
});
cy.get(`[row-id=${orderId}]`)
.find('[data-testid="edit"]')
.should('have.text', 'Edit')
.then(($btn) => {
cy.wrap($btn).click();
cy.getByTestId('dialog-title').should('have.text', 'Edit order');
cy.get('#limitPrice').focus().clear().type('0.111111');
cy.getByTestId('edit-order').find('[type="submit"]').click();
cy.getByTestId('input-error-text').should(
'have.text',
'Price accepts up to 5 decimal places'
);
});
});
it.skip('tbd for 7003-MORD', () => {
// NOT COVERED: must see the reference, offset and direction for each part pegged order - waiting for clarification
// NOT COVERED: must see the reference, offset and direction for each part liquidity order order - waiting for clarification
});
});
@@ -1,23 +1,18 @@
import { aliasGQLQuery } from '@vegaprotocol/cypress';
import {
assetsQuery,
ledgerEntriesQuery,
marketsQuery,
} from '@vegaprotocol/mock';
import { ledgerEntriesQuery } from '@vegaprotocol/mock';
describe('Portfolio page', { tags: '@smoke' }, () => {
beforeEach(() => {
cy.mockTradingPage();
cy.mockGQL((req) => {
aliasGQLQuery(req, 'LedgerEntries', ledgerEntriesQuery());
aliasGQLQuery(req, 'Assets', assetsQuery());
aliasGQLQuery(req, 'Markets', marketsQuery());
});
cy.mockSubscription();
cy.setVegaWallet();
});
describe('Ledger entries', () => {
it('List should be properly rendered', () => {
cy.visit('/#/portfolio');
cy.connectVegaWallet();
cy.getByTestId('"Ledger entries"').click();
const headers = [
'Sender',
@@ -1,25 +1,19 @@
beforeEach(() => {
cy.mockTradingPage();
cy.mockSubscription();
cy.setVegaWallet();
});
describe('positions', { tags: '@smoke' }, () => {
it('renders positions on trading page', () => {
cy.visit('/#/markets/market-0');
cy.getByTestId('Positions').click();
cy.getByTestId('tab-positions').should(
'contain.text',
'Connect your Vega wallet'
);
cy.connectVegaWallet();
validatePositionsDisplayed();
});
it('renders positions on portfolio page', () => {
cy.visit('/#/portfolio');
cy.getByTestId('Positions').click();
cy.connectVegaWallet();
validatePositionsDisplayed();
});
@@ -15,13 +15,11 @@ describe('withdraw form validation', { tags: '@smoke' }, () => {
cy.mockWeb3Provider();
cy.mockTradingPage();
cy.mockSubscription();
cy.setVegaWallet();
cy.visit('/#/portfolio');
cy.getByTestId('Withdrawals').click();
// Withdraw page requires vega wallet connection
cy.connectVegaWallet();
cy.getByTestId('withdraw-dialog-button').click();
// It also requires connection Ethereum wallet
@@ -72,13 +70,10 @@ describe('withdraw actions', { tags: '@regression' }, () => {
cy.mockWeb3Provider();
cy.mockTradingPage();
cy.mockSubscription();
cy.setVegaWallet();
cy.visit('/#/portfolio');
cy.getByTestId('Withdrawals').click();
// Withdraw page requires vega wallet connection
cy.connectVegaWallet();
cy.getByTestId('withdraw-dialog-button').click();
connectEthereumWallet();
@@ -1,11 +0,0 @@
import { ethers } from 'ethers';
import type { Transaction } from '@vegaprotocol/wallet';
/**
* Base64 encode a transaction object
*/
export const encodeTransaction = (tx: Transaction): string => {
return ethers.utils.base64.encode(
ethers.utils.toUtf8Bytes(JSON.stringify(tx))
);
};
@@ -7,7 +7,6 @@ import type {
OrderSubmissionBody,
Transaction,
} from '@vegaprotocol/wallet';
import { encodeTransaction } from './encode-transaction';
export const testOrderSubmission = (
order: OrderSubmission,
@@ -18,9 +17,6 @@ export const testOrderSubmission = (
...expected,
};
expectedOrder.expiresAt = expectedOrder.expiresAt || undefined;
expectedOrder.price = expectedOrder.price || undefined;
const transaction: OrderSubmissionBody = {
orderSubmission: expectedOrder,
};
@@ -36,9 +32,6 @@ export const testOrderAmendment = (
...expected,
};
expectedOrder.expiresAt = expectedOrder.expiresAt || undefined;
expectedOrder.price = expectedOrder.price || undefined;
const transaction: OrderAmendmentBody = {
orderAmendment: expectedOrder,
};
@@ -70,7 +63,7 @@ const vegaWalletTransaction = (transaction: Transaction) => {
?.token,
publicKey: Cypress.env('VEGA_PUBLIC_KEY2'),
sendingMode: 'TYPE_SYNC',
encodedTransaction: encodeTransaction(transaction),
transaction,
});
cy.getByTestId(dialogTitle).should(
'have.text',
Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

+17 -35
View File
@@ -1,14 +1,10 @@
import { marketsWithDataProvider } from '@vegaprotocol/market-list';
import {
addDecimalsFormatNumber,
titlefy,
useDataProvider,
} from '@vegaprotocol/react-helpers';
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
import { Links, Routes } from '../../pages/client-router';
import { useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import { useGlobalStore, usePageTitleStore } from '../../stores';
import { marketsWithDataProvider } from '@vegaprotocol/market-list';
import { useDataProvider } from '@vegaprotocol/react-helpers';
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
import { Links, Routes } from '../../pages/client-router';
import { useGlobalStore } from '../../stores';
export const Home = () => {
const navigate = useNavigate();
@@ -17,40 +13,26 @@ export const Home = () => {
const { data, error, loading } = useDataProvider({
dataProvider: marketsWithDataProvider,
});
const { update } = useGlobalStore((store) => ({
update: store.update,
}));
const { pageTitle, updateTitle } = usePageTitleStore((store) => ({
pageTitle: store.pageTitle,
updateTitle: store.updateTitle,
}));
const update = useGlobalStore((store) => store.update);
const marketId = useGlobalStore((store) => store.marketId);
useEffect(() => {
if (data) {
const marketId = data[0]?.id;
const marketName = data[0]?.tradableInstrument.instrument.name;
const marketPrice = data[0]?.data?.markPrice
? addDecimalsFormatNumber(
data[0]?.data?.markPrice,
data[0]?.decimalPlaces
)
: null;
const newPageTitle = titlefy([marketName, marketPrice]);
if (marketId) {
navigate(Links[Routes.MARKET](marketId), {
if (marketId) {
navigate(Links[Routes.MARKET](marketId), {
replace: true,
});
} else if (data) {
const marketDataId = data[0]?.id;
if (marketDataId) {
navigate(Links[Routes.MARKET](marketDataId), {
replace: true,
});
update({ marketId });
if (pageTitle !== newPageTitle) {
updateTitle(newPageTitle);
}
} else {
navigate(Links[Routes.MARKET]());
}
update({ shouldDisplayWelcomeDialog: true });
}
}, [data, navigate, update, pageTitle, updateTitle]);
}, [marketId, data, navigate, update]);
return (
<AsyncRenderer data={data} loading={loading} error={error}>
+122 -40
View File
@@ -2,15 +2,16 @@ import {
liquidityProvisionsDataProvider,
LiquidityTable,
lpAggregatedDataProvider,
marketLiquidityDataProvider,
useCheckLiquidityStatus,
} from '@vegaprotocol/liquidity';
import { tooltipMapping } from '@vegaprotocol/market-info';
import {
addDecimalsFormatNumber,
formatNumberPercentage,
NetworkParams,
t,
useDataProvider,
useNetworkParam,
useNetworkParams,
} from '@vegaprotocol/react-helpers';
import * as Schema from '@vegaprotocol/types';
import {
@@ -18,9 +19,10 @@ import {
Tab,
Tabs,
Link as UiToolkitLink,
Indicator,
} from '@vegaprotocol/ui-toolkit';
import { useVegaWallet } from '@vegaprotocol/wallet';
import { useCallback, useEffect, useMemo, useRef } from 'react';
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { Header, HeaderStat } from '../../components/header';
@@ -28,6 +30,13 @@ import type { AgGridReact } from 'ag-grid-react';
import type { LiquidityProvisionData } from '@vegaprotocol/liquidity';
import { Link, useParams } from 'react-router-dom';
import { Links, Routes } from '../../pages/client-router';
import type {
MarketData,
MarketDataUpdateFieldsFragment,
MarketDealTicket,
SingleMarketFieldsFragment,
} from '@vegaprotocol/market-list';
import { marketProvider, marketDataProvider } from '@vegaprotocol/market-list';
export const Liquidity = () => {
const params = useParams();
@@ -41,16 +50,47 @@ export const LiquidityContainer = ({
marketId: string | undefined;
}) => {
const gridRef = useRef<AgGridReact | null>(null);
const { data: marketProvision } = useDataProvider({
dataProvider: marketLiquidityDataProvider,
skipUpdates: true,
variables: useMemo(() => ({ marketId }), [marketId]),
const [market, setMarket] = useState<MarketDealTicket | null>(null);
const variables = useMemo(
() => ({
marketId: marketId,
}),
[marketId]
);
const { data: marketProvision } = useDataProvider<
SingleMarketFieldsFragment,
never
>({
dataProvider: marketProvider,
variables,
skip: !marketId,
});
const updateMarket = useCallback(
({ data: marketData }: { data: MarketData | null }) => {
if (marketData) {
setMarket({
...marketProvision,
data: marketData,
} as MarketDealTicket);
}
return true;
},
[marketProvision]
);
useDataProvider<MarketData, MarketDataUpdateFieldsFragment>({
dataProvider: marketDataProvider,
update: updateMarket,
variables,
skip: !marketId || !marketProvision,
});
const dataRef = useRef<LiquidityProvisionData[] | null>(null);
const { reload } = useDataProvider({
dataProvider: liquidityProvisionsDataProvider,
variables: useMemo(() => ({ marketId }), [marketId]),
variables,
});
const update = useCallback(
@@ -85,17 +125,14 @@ export const LiquidityContainer = ({
}, [reload]);
const assetDecimalPlaces =
marketProvision?.market?.tradableInstrument.instrument.product
.settlementAsset.decimals || 0;
market?.tradableInstrument.instrument.product.settlementAsset.decimals || 0;
const symbol =
marketProvision?.market?.tradableInstrument.instrument.product
.settlementAsset.symbol;
const { param: stakeToCcySiskas } = useNetworkParam(
NetworkParams.market_liquidity_stakeToCcySiskas
);
const stakeToCcySiska = stakeToCcySiskas && stakeToCcySiskas[0];
market?.tradableInstrument.instrument.product.settlementAsset.symbol;
const { params } = useNetworkParams([
NetworkParams.market_liquidity_stakeToCcyVolume,
]);
const stakeToCcyVolume = params.market_liquidity_stakeToCcyVolume;
const filteredEdges = useMemo(
() =>
liquidityProviders?.filter((e) =>
@@ -115,7 +152,7 @@ export const LiquidityContainer = ({
data={filteredEdges}
symbol={symbol}
assetDecimalPlaces={assetDecimalPlaces}
stakeToCcySiskas={stakeToCcySiska}
stakeToCcyVolume={stakeToCcyVolume}
/>
</AsyncRenderer>
);
@@ -128,10 +165,41 @@ export const LiquidityViewContainer = ({
}) => {
const { pubKey } = useVegaWallet();
const gridRef = useRef<AgGridReact | null>(null);
const { data: marketProvision } = useDataProvider({
dataProvider: marketLiquidityDataProvider,
skipUpdates: true,
variables: useMemo(() => ({ marketId }), [marketId]),
const [market, setMarket] = useState<MarketDealTicket | null>(null);
const variables = useMemo(
() => ({
marketId: marketId,
}),
[marketId]
);
const { data: marketProvision } = useDataProvider<
SingleMarketFieldsFragment,
never
>({
dataProvider: marketProvider,
variables,
skip: !marketId,
});
const updateMarket = useCallback(
({ data: marketData }: { data: MarketData | null }) => {
if (marketData) {
setMarket({
...marketProvision,
data: marketData,
} as MarketDealTicket);
}
return true;
},
[marketProvision]
);
useDataProvider<MarketData, MarketDataUpdateFieldsFragment>({
dataProvider: marketDataProvider,
update: updateMarket,
variables,
skip: !marketId || !marketProvision,
});
const dataRef = useRef<LiquidityProvisionData[] | null>(null);
@@ -171,20 +239,20 @@ export const LiquidityViewContainer = ({
return () => clearInterval(interval);
}, [reload]);
const targetStake = marketProvision?.market?.data?.targetStake;
const suppliedStake = marketProvision?.market?.data?.suppliedStake;
const targetStake = market?.data?.targetStake;
const suppliedStake = market?.data?.suppliedStake;
const assetDecimalPlaces =
marketProvision?.market?.tradableInstrument.instrument.product
.settlementAsset.decimals || 0;
market?.tradableInstrument.instrument.product.settlementAsset.decimals || 0;
const symbol =
marketProvision?.market?.tradableInstrument.instrument.product
.settlementAsset.symbol;
const { param: stakeToCcySiskas } = useNetworkParam(
NetworkParams.market_liquidity_stakeToCcySiskas
);
const stakeToCcySiska = stakeToCcySiskas && stakeToCcySiskas[0];
market?.tradableInstrument.instrument.product.settlementAsset.symbol;
const { params } = useNetworkParams([
NetworkParams.market_liquidity_stakeToCcyVolume,
NetworkParams.market_liquidity_targetstake_triggering_ratio,
]);
const stakeToCcyVolume = params.market_liquidity_stakeToCcyVolume;
const triggeringRatio =
params.market_liquidity_targetstake_triggering_ratio || '1';
const myLpEdges = useMemo(
() => liquidityProviders?.filter((e) => e.party.id === pubKey),
[liquidityProviders, pubKey]
@@ -221,18 +289,24 @@ export const LiquidityViewContainer = ({
return LiquidityTabs.Active;
};
const { percentage, status } = useCheckLiquidityStatus({
suppliedStake: suppliedStake || 0,
targetStake: targetStake || 0,
triggeringRatio,
});
return (
<AsyncRenderer loading={loading} error={error} data={liquidityProviders}>
<div className="h-full grid grid-rows-[min-content_1fr]">
<Header
title={
marketProvision?.market?.tradableInstrument.instrument.name &&
market?.tradableInstrument.instrument.name &&
marketId && (
<Link to={Links[Routes.MARKET](marketId)}>
<UiToolkitLink className="sm:text-lg md:text-xl lg:text-2xl flex items-center gap-2 whitespace-nowrap hover:text-neutral-500 dark:hover:text-neutral-300">
{`${
marketProvision?.market?.tradableInstrument.instrument.name
} ${t('liquidity provision')}`}
{`${market?.tradableInstrument.instrument.name} ${t(
'liquidity provision'
)}`}
</UiToolkitLink>
</Link>
)
@@ -264,6 +338,14 @@ export const LiquidityViewContainer = ({
: '-'}
</div>
</HeaderStat>
<HeaderStat
heading={t('Liquidity supplied')}
testId="liquidity-supplied"
>
<Indicator variant={status} />
{formatNumberPercentage(percentage, 2)}
</HeaderStat>
<HeaderStat heading={t('Market ID')}>
<div className="break-word">{marketId}</div>
</HeaderStat>
@@ -279,7 +361,7 @@ export const LiquidityViewContainer = ({
ref={gridRef}
data={myLpEdges}
symbol={symbol}
stakeToCcySiskas={stakeToCcySiska}
stakeToCcyVolume={stakeToCcyVolume}
assetDecimalPlaces={assetDecimalPlaces}
/>
)}
@@ -291,7 +373,7 @@ export const LiquidityViewContainer = ({
data={activeEdges}
symbol={symbol}
assetDecimalPlaces={assetDecimalPlaces}
stakeToCcySiskas={stakeToCcySiska}
stakeToCcyVolume={stakeToCcyVolume}
/>
)}
</Tab>
@@ -303,7 +385,7 @@ export const LiquidityViewContainer = ({
data={inactiveEdges}
symbol={symbol}
assetDecimalPlaces={assetDecimalPlaces}
stakeToCcySiskas={stakeToCcySiska}
stakeToCcyVolume={stakeToCcyVolume}
/>
)}
</Tab>
+20 -21
View File
@@ -32,29 +32,23 @@ export interface SingleMarketData extends SingleMarketFieldsFragment {
}
export const Market = () => {
const params = useParams();
const { marketId } = useParams();
const navigate = useNavigate();
const marketId = params.marketId;
const { w } = useWindowSize();
const { update } = useGlobalStore((store) => ({
update: store.update,
}));
const update = useGlobalStore((store) => store.update);
const lastMarketId = useGlobalStore((store) => store.marketId);
const { pageTitle, updateTitle } = usePageTitleStore((store) => ({
pageTitle: store.pageTitle,
updateTitle: store.updateTitle,
}));
const pageTitle = usePageTitleStore((store) => store.pageTitle);
const updateTitle = usePageTitleStore((store) => store.updateTitle);
const onSelect = useCallback(
(id: string) => {
if (id && id !== marketId) {
update({ marketId: id });
navigate(Links[Routes.MARKET](id));
}
},
[marketId, update, navigate]
[marketId, navigate]
);
const variables = useMemo(
@@ -64,12 +58,22 @@ export const Market = () => {
[marketId]
);
const updateMarketId = useCallback(
({ data }: { data: { id?: string } | null }) => {
if (data?.id && data.id !== lastMarketId) {
update({ marketId: data.id });
}
return true;
},
[update, lastMarketId]
);
const { data, error, loading } = useDataProvider<
SingleMarketFieldsFragment,
never
>({
dataProvider: marketProvider,
variables,
update: updateMarketId,
skip: !marketId,
});
@@ -104,11 +108,10 @@ export const Market = () => {
}
return <TradePanels market={data} onSelect={onSelect} />;
}, [w, data, onSelect]);
if (!data && marketId) {
return (
<Splash>
<p>{t('Not found')}</p>
<p>{t('Market not found')}</p>
</Splash>
);
}
@@ -119,13 +122,9 @@ export const Market = () => {
error={error}
data={data || undefined}
noDataCondition={(data) => false}
render={(data) => {
if (!data && marketId) {
return <Splash>{t('Market not found')}</Splash>;
}
return <>{tradeView}</>;
}}
/>
>
{tradeView}
</AsyncRenderer>
);
};
@@ -83,7 +83,7 @@ const MainGrid = ({
>
<TradeGridChild>
<Tabs>
<Tab id="candles" name={t('Candles')}>
<Tab id="chart" name={t('Chart')}>
<TradingViews.Candles marketId={marketId} />
</Tab>
<Tab id="depth" name={t('Depth')}>
@@ -17,6 +17,7 @@ import { Last24hPriceChange } from '../../components/last-24h-price-change';
import { Last24hVolume } from '../../components/last-24h-volume';
import { MarketState } from '../../components/market-state';
import { MarketTradingMode } from '../../components/market-trading-mode';
import { MarketLiquiditySupplied } from '../../components/liquidity-supplied';
interface TradeMarketHeaderProps {
market: SingleMarketFieldsFragment | null;
@@ -96,6 +97,10 @@ export const TradeMarketHeader = ({
</HeaderStat>
) : null}
<MarketProposalNotification marketId={market?.id} />
<MarketLiquiditySupplied
marketId={market?.id}
assetDecimals={asset?.decimals || 0}
/>
</Header>
);
};
@@ -1,18 +1,15 @@
import { useCallback } from 'react';
import { MarketsContainer } from '@vegaprotocol/market-list';
import { useGlobalStore } from '../../stores';
import { useNavigate } from 'react-router-dom';
import { Links, Routes } from '../../pages/client-router';
export const Markets = () => {
const navigate = useNavigate();
const { update } = useGlobalStore((store) => ({ update: store.update }));
const handleOnSelect = useCallback(
(marketId: string) => {
update({ marketId });
navigate(Links[Routes.MARKET](marketId));
},
[update, navigate]
[navigate]
);
return <MarketsContainer onSelect={handleOnSelect} />;
@@ -151,7 +151,11 @@ const AccountHistoryManager = ({
: t('Select account type')}
</DropdownMenuTrigger>
<DropdownMenuContent>
{Object.keys(Schema.AccountType).map((type) => (
{[
Schema.AccountType.ACCOUNT_TYPE_GENERAL,
Schema.AccountType.ACCOUNT_TYPE_BOND,
Schema.AccountType.ACCOUNT_TYPE_MARGIN,
].map((type) => (
<DropdownMenuItem
key={type}
onClick={() => setAccountType(type as Schema.AccountType)}
@@ -0,0 +1 @@
export * from './liquidity-supplied';
@@ -0,0 +1,145 @@
import { useCallback, useMemo, useState } from 'react';
import {
addDecimalsFormatNumber,
formatNumberPercentage,
NetworkParams,
t,
useDataProvider,
useNetworkParams,
} from '@vegaprotocol/react-helpers';
import type {
MarketData,
MarketDataUpdateFieldsFragment,
SingleMarketFieldsFragment,
} from '@vegaprotocol/market-list';
import { marketDataProvider, marketProvider } from '@vegaprotocol/market-list';
import { HeaderStat } from '../header';
import { Indicator, Link } from '@vegaprotocol/ui-toolkit';
import BigNumber from 'bignumber.js';
import { useCheckLiquidityStatus } from '@vegaprotocol/liquidity';
import { DataGrid } from '@vegaprotocol/react-helpers';
import { AuctionTrigger, MarketTradingMode } from '@vegaprotocol/types';
interface Props {
marketId?: string;
noUpdate?: boolean;
assetDecimals: number;
}
export const MarketLiquiditySupplied = ({
marketId,
assetDecimals,
noUpdate = false,
}: Props) => {
const [market, setMarket] = useState<MarketData>();
const { params } = useNetworkParams([
NetworkParams.market_liquidity_stakeToCcyVolume,
NetworkParams.market_liquidity_targetstake_triggering_ratio,
]);
const stakeToCcyVolume = params.market_liquidity_stakeToCcyVolume;
const triggeringRatio = Number(
params.market_liquidity_targetstake_triggering_ratio
);
const variables = useMemo(
() => ({
marketId: marketId,
}),
[marketId]
);
const { data } = useDataProvider<SingleMarketFieldsFragment, never>({
dataProvider: marketProvider,
variables,
skip: !marketId,
});
const update = useCallback(
({ data: marketData }: { data: MarketData | null }) => {
if (!noUpdate && marketData) {
setMarket(marketData);
}
return true;
},
[noUpdate]
);
useDataProvider<MarketData, MarketDataUpdateFieldsFragment>({
dataProvider: marketDataProvider,
update,
variables,
skip: noUpdate || !marketId || !data,
});
const supplied = market?.suppliedStake
? addDecimalsFormatNumber(
new BigNumber(market?.suppliedStake)
.multipliedBy(stakeToCcyVolume || 1)
.toString(),
assetDecimals
)
: '-';
const { percentage, status } = useCheckLiquidityStatus({
suppliedStake: market?.suppliedStake || 0,
targetStake: market?.targetStake || 0,
triggeringRatio,
});
const compiledGrid = [
{
label: t('Supplied stake'),
value: market?.suppliedStake
? addDecimalsFormatNumber(
new BigNumber(market?.suppliedStake).toString(),
assetDecimals
)
: '-',
},
{
label: t('Target stake'),
value: market?.targetStake
? addDecimalsFormatNumber(
new BigNumber(market?.targetStake).toString(),
assetDecimals
)
: '-',
},
];
const showMessage =
percentage.gte(100) &&
market?.marketTradingMode ===
MarketTradingMode.TRADING_MODE_MONITORING_AUCTION &&
market.trigger === AuctionTrigger.AUCTION_TRIGGER_LIQUIDITY;
const description = (
<section>
{compiledGrid && <DataGrid grid={compiledGrid} />}
<br />
<Link href={`/#/liquidity/${marketId}`} data-testid="view-liquidity-link">
{t('View liquidity provision table')}
</Link>
{showMessage && (
<p className="mt-4">
{t(
'The market is in an auction because there are no priced limit orders, which are required to deploy liquidity commitment pegged orders. This means the order book is empty on one or both sides.'
)}
</p>
)}
</section>
);
return (
<HeaderStat
heading={t('Liquidity supplied')}
description={description}
testId="liquidity-supplied"
>
<Indicator variant={status} />
{supplied} (
{percentage.gt(100) ? '>100%' : formatNumberPercentage(percentage, 2)})
</HeaderStat>
);
};
@@ -1,4 +1,4 @@
import React, { useMemo, useState, useCallback } from 'react';
import React, { useCallback } from 'react';
import { useLocation } from 'react-router-dom';
import { Dialog } from '@vegaprotocol/ui-toolkit';
import {
@@ -12,59 +12,50 @@ import * as constants from '../constants';
import { RiskNoticeDialog } from './risk-notice-dialog';
import { WelcomeNoticeDialog } from './welcome-notice-dialog';
import { WelcomeLandingDialog } from './welcome-landing-dialog';
import { useGlobalStore } from '../../stores';
interface DialogConfig {
open?: boolean;
content: React.ReactNode;
title?: string;
size?: 'small' | 'medium';
onClose: () => void;
}
export const WelcomeDialog = () => {
const { pathname } = useLocation();
const { VEGA_ENV } = useEnvironment();
const [dialog, setDialog] = useState<DialogConfig | null>(null);
const onClose = useCallback(() => {
setDialog(null);
}, [setDialog]);
let dialogContent: React.ReactNode = null;
let title = '';
let size: 'small' | 'medium' = 'small';
const [riskAccepted] = useLocalStorage(constants.RISK_ACCEPTED_KEY);
const { data } = useDataProvider({
dataProvider: activeMarketsProvider,
});
useMemo(() => {
switch (true) {
case riskAccepted !== 'true' && VEGA_ENV === Networks.MAINNET:
setDialog({
content: <RiskNoticeDialog onClose={onClose} />,
title: t('WARNING'),
size: 'medium',
onClose,
});
break;
case pathname === '/' && data?.length === 0:
setDialog({
content: <WelcomeNoticeDialog />,
onClose,
});
break;
case pathname === '/' && (data?.length || 0) > 0:
setDialog({
content: <WelcomeLandingDialog onClose={onClose} />,
onClose,
});
break;
}
}, [onClose, data?.length, riskAccepted, pathname, VEGA_ENV, setDialog]);
return dialog ? (
const { update, shouldDisplayWelcomeDialog } = useGlobalStore((store) => ({
update: store.update,
shouldDisplayWelcomeDialog: store.shouldDisplayWelcomeDialog,
}));
const isRiskDialogNeeded =
riskAccepted !== 'true' && VEGA_ENV === Networks.MAINNET;
const isWelcomeDialogNeeded = pathname === '/' || shouldDisplayWelcomeDialog;
const onClose = useCallback(() => {
update({ shouldDisplayWelcomeDialog: isRiskDialogNeeded });
// eslint-disable-next-line react-hooks/exhaustive-deps
dialogContent = null;
}, [update, isRiskDialogNeeded]);
if (isRiskDialogNeeded) {
dialogContent = <RiskNoticeDialog onClose={onClose} />;
title = t('WARNING');
size = 'medium';
} else if (isWelcomeDialogNeeded && data?.length === 0) {
dialogContent = <WelcomeNoticeDialog />;
} else if (isWelcomeDialogNeeded && (data?.length || 0) > 0) {
dialogContent = <WelcomeLandingDialog onClose={onClose} />;
}
return (
<Dialog
open={Boolean(dialog.content)}
title={dialog.title}
size={dialog.size}
onChange={dialog.onClose}
open={Boolean(dialogContent)}
title={title}
size={size}
onChange={onClose}
>
{dialog.content}
{dialogContent}
</Dialog>
) : null;
);
};
@@ -12,7 +12,6 @@ import {
} from '../select-market';
import { WelcomeDialogHeader } from './welcome-dialog-header';
import { Link, useNavigate, useParams } from 'react-router-dom';
import { useGlobalStore } from '../../stores';
import { ProposedMarkets } from './proposed-markets';
import { Links, Routes } from '../../pages/client-router';
@@ -27,18 +26,13 @@ export const SelectMarketLandingTable = ({
const navigate = useNavigate();
const marketId = params.marketId;
const { update } = useGlobalStore((store) => ({
update: store.update,
}));
const onSelect = useCallback(
(id: string) => {
if (id && id !== marketId) {
update({ marketId: id });
navigate(Links[Routes.MARKET](id));
}
},
[marketId, update, navigate]
[marketId, navigate]
);
const onSelectMarket = useCallback(

Some files were not shown because too many files have changed in this diff Show More