Compare commits

..
Author SHA1 Message Date
Dariusz Majcherczyk 17bc4541e9 chore: multi click for toast 2023-01-29 19:51:12 +01:00
Dariusz Majcherczyk 2bd8044a6c chore: reverted proper assertion 2023-01-29 16:03:16 +01:00
Dariusz Majcherczyk b3a82fd6f0 chore: capsule tests refactor and increase deposit AC test coverage 2023-01-29 14:09:43 +01:00
mattrussell36 f22fb56afd chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-29 12:06:12 +00:00
mattrussell36 f2627e6ebf chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-29 06:07:03 +00:00
mattrussell36 24e6a13d93 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-29 00:13:02 +00:00
mattrussell36 b56050ad1c chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-28 18:07:37 +00:00
mattrussell36 cff83ed062 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-28 12:06:05 +00:00
mattrussell36 8ecce874b0 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-28 06:08:30 +00:00
Bartłomiej Głownia 00e319b3c6 chore: handle not found errors as correct response (#2759) 2023-01-27 18:35:45 -08:00
mattrussell36 05559f3ea0 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-28 00:11:14 +00:00
m.ray 4b3b5c322a fix: trades grid colors (#2766) 2023-01-27 18:55:20 +00:00
Bartłomiej Głownia b1280c8285 fix: hide close button if openVolume is zero (#2768) 2023-01-27 18:44:20 +00:00
Edd 1e0e1c7859 feat(explorer): add long text component for hashes and tx viewer (#2765) 2023-01-27 18:37:59 +00:00
mattrussell36 ec2bb81ec8 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-27 18:08:36 +00:00
m.ray fe95c6fcbc fix: show markets link & deal ticket validation (#2763) 2023-01-27 18:10:20 +01:00
macqbat 853ec8f69c chore(2351): improve handling wallet errors (#2729) 2023-01-27 15:45:29 +01:00
mattrussell36 b68c090ee5 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-27 12:09:03 +00:00
Matthew Russellandasiaznik cb9b811730 feat(#1791): block height check (#2701)
Co-authored-by: asiaznik <artur@vegaprotocol.io>
2023-01-27 11:31:23 +01:00
Bartłomiej Głownia 98b5260d93 feat: fix positions and margins providers update (#2753) 2023-01-27 09:39:39 +01:00
mattrussell36 613262f7a5 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-27 06:05:57 +00:00
mattrussell36 9ae6f5201c chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-27 00:10:54 +00:00
m.ray cfb75fcf8f fix: volume charts position dp (#2756) 2023-01-26 19:36:29 +00:00
mattrussell36 ae6ccdfb52 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-26 18:08:18 +00:00
Radosław Szpiech 9e73c6a462 chore: 2593 trading-e2e refactor - split global.cy (#2754) 2023-01-26 17:50:33 +01:00
Edd 24c017bc2b feat(explorer): add basic votesubmission tx view (#2694) 2023-01-26 14:53:34 +00:00
Edd 3188f23439 fix(explorer): place sensible limits on oracles page queries (#2699) 2023-01-26 14:50:52 +00:00
Edd 33e528c569 fix(explorer): switch decimals used in lp commitment views (#2747) 2023-01-26 14:47:31 +00:00
Radosław Szpiech e10945eeda chore: correct ethereum releated envs in trading-e2e (#2744) 2023-01-26 15:40:49 +01:00
m.ray 47b2a2fdcb fix: volume chart values fixing - position dp (#2749) 2023-01-26 14:21:43 +00:00
m.ray 860938f26c fix: market selected no longer available - add link to all markets (#2748) 2023-01-26 13:46:44 +00:00
Art 5766d84804 fix: select position (#2745) 2023-01-26 12:36:47 +00:00
mattrussell36 6362c022b5 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-26 12:06:16 +00:00
Bartłomiej Głownia a6118c14dd feat: fix EthTxCompletedToastContent (#2741) 2023-01-26 12:00:00 +00:00
Sam Keen d384fb35f1 feat(2396): token delegations pagination (#2575) 2023-01-26 10:20:26 +00:00
Ciaran McGhie 3ed3714e79 fix(#2216): lp-dashboard grab market close from metadata (#2564) 2023-01-26 09:58:39 +00:00
Matthew Russell 3893b26d30 fix: dropdown menu portals (#2740) 2023-01-26 09:52:49 +01:00
mattrussell36 1ba0ad234b chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-26 06:07:07 +00:00
mattrussell36 9f6a5aac39 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-26 00:13:06 +00:00
Bartłomiej GłowniaandMatthew Russell 129274a8e6 feat: add seperate transaction toast for completed eth transaction (#2733)
Co-authored-by: Matthew Russell <mattrussell36@gmail.com>
2023-01-25 12:25:44 -08:00
Bartłomiej Głownia 3fadda15fd chore: remove sentry captureException in marketDepthProvider update (#2713) 2023-01-25 11:58:37 -08:00
m.rayandasiaznik 7ea7edc1e2 feat(#2565): orderbook populate limit (#2690)
Co-authored-by: asiaznik <artur@vegaprotocol.io>
2023-01-25 11:38:26 -08:00
Edd dad953b45b fix(explorer): fix various small lp tx view bugs (#2738) 2023-01-25 18:18:59 +00:00
mattrussell36 ed1363b035 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-25 18:08:10 +00:00
Art b2ab4f49d9 feat: rich asset details dropdown (2557) (#2711) 2023-01-25 14:24:53 +00:00
Edd a60379b40f feat(explorer): data submission tx view (#2698) 2023-01-25 13:33:12 +00:00
mattrussell36 7db2a58f9d chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-25 12:08:53 +00:00
m.ray 7279556bf7 feat(#2599): liquidity price range added in market info (#2716) 2023-01-25 13:42:29 +02:00
Dexter Edwards 52cc2ef7df fix: add risk parameters (#2706) 2023-01-25 10:36:22 +00:00
macqbat a218da93a6 feat: logging - working solution (#2696) 2023-01-25 09:43:11 +01:00
daro-maj 10fe82dea8 chore: deposit and withdrawal capsule e2e tests (#2720) 2023-01-25 08:21:17 +01:00
mattrussell36 b0de4dfbf3 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-25 06:06:42 +00:00
Matthew Russell cd0e2e41a8 chore(#2668): use ui-toolkit checkbox for orderbook (#2702) 2023-01-24 21:49:59 -08:00
mattrussell36 dc3330d55e chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-25 00:12:48 +00:00
Matthew Russell a016feab2a fix: dont use current value in update callback for estimate queries (#2721) 2023-01-24 21:33:55 +00:00
mattrussell36 68446ccf65 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-24 18:08:20 +00:00
Matthew Russell c7aec5cfcb chore: add cypress files to ignore list and use glob ignore option (#2700) 2023-01-24 08:06:46 -08:00
Radosław Szpiech f58144d785 chore: fix skip cache typo in workflow (#2715) 2023-01-24 15:59:53 +00:00
Dexter Edwards 415b902f53 feat: splash loader more central (#2707) 2023-01-24 14:02:43 +00:00
165b131b27 chore: move token's web3 url connector to web3 lib (#2655)
Co-authored-by: Dexter <dexter.edwards93@gmail.com>
Co-authored-by: Dariusz Majcherczyk <dariusz.majcherczyk@gmail.com>
2023-01-24 14:02:17 +00:00
Bartłomiej Głownia 0cff5895c7 feat: call update with null data from useDataProvider hook on variables change (#2689) 2023-01-24 14:01:51 +00:00
Dexter Edwards 31881f8e5a fix: calculation of required stake (#2687) 2023-01-24 14:00:38 +00:00
Art 346af6118d chore: consolidate persisted order entries (#2673) 2023-01-24 13:56:12 +00:00
Dexter Edwards bcbc3bb146 fix: adjust route strcuture (#2708) 2023-01-24 13:44:11 +00:00
Radosław Szpiech d7440cfe54 chore: correct runner name (#2710) 2023-01-24 13:25:29 +01:00
mattrussell36 801606e37f chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-24 12:08:25 +00:00
Dexter Edwards 01e7b8caee fix: show error message correctly (#2705) 2023-01-24 11:29:42 +00:00
Joe Tsang e883ef5c5e test(#2639): e2e view public key tests (#2688) 2023-01-24 10:52:01 +00:00
mattrussell36 2f391cde5b chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-24 06:07:12 +00:00
mattrussell36 3620314dca chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-24 00:11:13 +00:00
mattrussell36 9bdd1ed387 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-23 18:06:31 +00:00
mattrussell36 37dc8bf110 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-23 12:08:39 +00:00
Edd 3754043f8b fix(explorer): add correct tendermint websocket url
Fairground block explorer seems subtly broken (block count not increasing) because this value is incorrect
2023-01-23 11:44:44 +00:00
mattrussell36 1ee45b6135 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-23 06:08:42 +00:00
mattrussell36 a51410c722 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-23 00:10:33 +00:00
mattrussell36 91173d2434 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-22 18:08:06 +00:00
mattrussell36 8dd33c285e chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-22 12:07:38 +00:00
mattrussell36 6a7385823a chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-22 06:06:12 +00:00
mattrussell36 9053b343d1 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-22 00:11:09 +00:00
mattrussell36 6562107578 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-21 18:08:23 +00:00
mattrussell36 8f5bedc12a chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-21 12:08:20 +00:00
mattrussell36 3044f3bdf7 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-21 06:08:34 +00:00
mattrussell36 5eb8fb64c7 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-21 00:10:21 +00:00
botond ae84e16b9b chore: bump wallet client (#2662) 2023-01-20 20:05:18 +00:00
mattrussell36 5e5cc1c587 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-20 18:08:38 +00:00
mattrussell36 a3aa84b983 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-20 12:12:31 +00:00
Radosław Szpiech 49374c8e7c chore: simplify cypress workflows (#2677) 2023-01-20 10:21:22 +00:00
mattrussell36 8f4eeba092 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-20 06:07:47 +00:00
mattrussell36 66cceb0f34 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-20 00:12:41 +00:00
Matthew Russell b34fc98c9c chore: make headers consistent (#2683) 2023-01-19 22:15:55 +00:00
m.ray e4ada295e2 fix(#2345): positions table link to markets (#2652) 2023-01-19 13:53:10 -08:00
Art 805e8fbee7 chore: focus on toggle (2562) (#2678) 2023-01-19 18:43:58 +00:00
Edd 24fafe5a34 feat(explorer): add liquidity cancel view (#2680) 2023-01-19 18:43:35 +00:00
m.ray df4cea8e00 feat(#2661): show status on all markets list (#2669) 2023-01-19 10:09:24 -08:00
m.ray 52b25b8b15 fix: explorer header remove w-full network switcher (#2679) 2023-01-19 18:06:51 +00:00
Dexter Edwards b65db3cdad chore: remove console lite (#2670) 2023-01-19 16:59:49 +01:00
Edd 020d2e4e68 feat(explorer): reduce footer noise (#2676) 2023-01-19 15:31:56 +00:00
Art 5ccef2de5e feat: deposit and deal ticket transaction stores and toasts (#2495) 2023-01-19 13:10:52 +01:00
mattrussell36 4ce2924380 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-19 12:07:41 +00:00
Dexter Edwards f5b345636c feat: view apps as any pub key (#2548) 2023-01-19 11:16:21 +00:00
Matthew Russell c533c584da chore: tidy market setup scripts (#2657) 2023-01-19 09:52:38 +00:00
mattrussell36 c1ebda9274 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-19 06:06:49 +00:00
mattrussell36 1b2c0e8f8b chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-19 00:12:28 +00:00
Eddandm.ray df6b9023f1 feat(explorer): add liquidity provision submission and amend view (#2663)
Co-authored-by: m.ray <16125548+MadalinaRaicu@users.noreply.github.com>
2023-01-18 19:13:39 +00:00
mattrussell36 0702a97b6d chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-18 18:08:06 +00:00
m.ray c552a22af8 feat(#2560): show market code and name in the trading header (#2659) 2023-01-18 17:39:55 +00:00
m.rayandmacqbat fbdcd04096 chore(#2618): rename fields in ledger entry query (#2658) (#2660)
Co-authored-by: macqbat <maciek@vegaprotocol.io>
2023-01-18 13:14:06 +00:00
mattrussell36 89d0723eb3 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-18 12:07:58 +00:00
mattrussell36 f163a270d1 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-18 06:06:09 +00:00
mattrussell36 e04314608f chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-18 00:12:54 +00:00
mattrussell36 61c91c3542 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-17 18:06:53 +00:00
m.ray 2a9f3c7568 fix: liquidation est. should update on price change (#2649)
* fix: liquidation close out price needs to update when price updates on limit orders

* fix(#2624): add test case on limit sell order
2023-01-17 16:31:39 +00:00
Joe Tsang 2640b7d77d chore: update proposal detail tests (#2648) 2023-01-17 16:18:51 +00:00
Radosław Szpiech 2b229cd1e7 chore: add package json to hash (#2651) 2023-01-17 17:01:01 +01:00
Radosław Szpiech d098ee671e chore: add job name to log file name (#2650) 2023-01-17 16:47:03 +01:00
2c3c685522 feat(#2255): capsule tests for trading (#2498)
* feat: improve proposal types, add faucet for trading asset

* chore: yarn lock update

* fix: capsule tests to avoid jsx import

* chore: throw error so that ethereum setup failure is caught

* chore: org files and add logging

* chore: revert current trading-e2e .env file

* chore: add .env.capsule for trading tests on capsule

* chore: remove unused nx command

* chore: remove try catchs and allow errors to be caught by cypress

* chore: add slow tag for capsule test

* feat: move create market setup to libs/cypress

* chore: clearly separate vars meant for capsule with vars meant for non-capsule

* feat: remove hardcoded urls and use config obj

* chore: fix missing comma in genesis.tmpl

* chore: added limit order edit price test

* chore: remove encoding of transaction, update proposal tx trigger ratio to string

* chore: fix date and add date verification for update order

* chore: formatting fix

* chore: adjust trading app tests and workflows to be run in capsule in ci (#2574)

* chore: adjust trading app tests and workflows to be run in capsule in ci

* chore: fix token tests

* chore: increase timeout as it fails in ci

* chore: move market check to before function

* chore: add capsule logs to trading

* chore: increase proposal close time, also break up script for better debugging

* chore: bump up ethereum account setup timeout

* chore: suppress fetch logs to help with debugging

* chore: revert cy wraps now with suppressed logging

* chore: decrease tick amount

* chore: promise with timeout for better debugging

* chore: bump individual timeouts

* chore: bump timeout for tx wait promises

* chore: minor fix

* fix: leave Promise<any>

* fix: leave Promise<any>

* chore: fix home fail

Co-authored-by: Joe <joe@vega.xyz>
Co-authored-by: Dariusz Majcherczyk <dariusz.majcherczyk@gmail.com>
Co-authored-by: Radosław Szpiech <szpiechrados@gmail.com>
Co-authored-by: Madalina Raicu <madalina@raygroup.uk>
2023-01-17 16:33:43 +01:00
Sam Keen b96e6ee9ce feat(2633): remove unneeded values in validator detail view (#2644)
* feat(2633): remove overstaked amount

* feat(2633): remove performance score
2023-01-17 15:01:51 +00:00
Bartłomiej Głownia 1a6266e2ec chore: fix data and no data message update issues in trading data grids (#2620) 2023-01-17 15:01:24 +00:00
m.rayandRado c70ec7676e fix(#2569): market id copy update (#2627)
* fix(#2569): market id copy update

* fix: enable cell text selection on ag-grid by default

* chore: fix partially filled order test

Co-authored-by: Rado <szpiechrados@gmail.com>
2023-01-17 13:59:34 +00:00
macqbat 5e97391d53 chore(2559): filter ledger entries by account type (#2631)
* chore: ledger entries - add account type filters

* chore: ledger entries filtering - add int test

* chore: ledger entries filtering - fix linter fails

* chore: ledger entries filtering - fix int test failing

* chore: ledger entries filtering - fix int test failing
2023-01-17 13:44:23 +00:00
mattrussell36 8eebd814ae chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-17 12:08:17 +00:00
Ciaran McGhie bd754d1103 chore: 0 decimal places for % target stake column (#2588) 2023-01-17 11:10:20 +00:00
m.ray e362d06b5a fix: asset dropdown list (#2622)
* fix(#2556): asset dropdown list fix

* fix: add ID to market list and make cell copyable

* fix: revert market list table
2023-01-17 10:02:46 +00:00
macqbatandMatthew Russell 45a4dd7009 feat: mobile navbar on Console (#2547)
* feat: mobile navbar on Console

* feat: mobile navbar on Console - adjust unit test

* feat: mobile navbar on Console - adjust unit test

* feat: mobile navbar on Console - adjust themes

* feat: mobile navbar on Console - add some unit tests

* feat: mobile navbar on Console - refactor solution

* feat: mobile navbar on Console - adjust int tests

* feat: mobile navbar on Console - adjust styling

* feat: mobile navbar on Console - move close button into the drawer

* feat: mobile navbar on Console - adjust int tests

* chore: close drawe after navigation

* chore: mobile navbar on Console - adjust unit tests

* chore: mobile navbar on Console - adjust unit tests

Co-authored-by: Matthew Russell <mattrussell36@gmail.com>
2023-01-17 10:59:12 +01:00
Edd ff53e5e841 feat(explorer): batch market instructions (#2617)
* feat(explorer): add basic table for all types in a batch
* feat(explorer): use marketlink for market ids in batch
* feat(explorer): add ordersummary
* feat(explorer): improve caching with some slight overfetching and cache config
2023-01-17 09:51:42 +00:00
Sam Keen cd0ed05eb8 feat(2629): validator table - adjust the overstaked amount calculation (#2630) 2023-01-17 09:01:44 +00:00
mattrussell36 89f41a4500 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-17 06:08:44 +00:00
mattrussell36 38fdc91444 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-17 00:12:39 +00:00
mattrussell36 f8f523eb9c chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-16 18:08:44 +00:00
Bartłomiej Głownia 5a0da4e158 feat: update market data components when they are in view (#2607) 2023-01-16 17:51:30 +00:00
candida-d 4f7b589cbd fix: make validator text terminology match (#2626) 2023-01-16 17:36:40 +00:00
m.rayandcandida-d e5bf54ca02 fix: market expiry & trading live copy (#2619)
* fix(#2602): market expiry tooltip

* fix(#2612): update live trading copy

* fix: show - liq. supplied and fix lint issue

* fix: on-chain functionality tooltip

* Update apps/trading/components/welcome-dialog/welcome-notice-dialog.tsx

Co-authored-by: candida-d <62548908+candida-d@users.noreply.github.com>

* fix: propose a market link

Co-authored-by: candida-d <62548908+candida-d@users.noreply.github.com>
2023-01-16 17:36:06 +00:00
Edd 866a11fd89 feat(explorer): bring back oracles view (#2551)
* build(explorer): enable oracles view by default

* feat(explorer): restore and update oracles view

* feat(explorer): dumb and in need of refactor oracles tables

* feat(oracles): disable key view and rejig table

* feat(oracles): filter all JSON views to remove typename

* chore(explorer): oracles component refactor

* test(explorer): add tests for oracle markets component

* test(explorer): add tests for oracle signers component
2023-01-16 14:03:02 +00:00
Matthew Russell b10effa3c7 chore: add link to etherscan for asset dialog contract address (#2561)
* chore: add link to etherscan for asset dialog contract address

* chore: use useEtherscanLink hook

* chore: fix unused import
2023-01-16 13:11:51 +00:00
Sam Keen 1f1ca510f4 feat(2432): minor proposal detail display improvements (#2616)
* feat(2432): minor proposal detail display improvements

* feat(2432): unit tests updated
2023-01-16 12:35:10 +00:00
Bartłomiej Głownia 06151c0592 feat: add marketId to orders query (#2536)
* feat: add marketId to orders query

* feat: move filters handling from useOrderListData to ordersProvider
2023-01-16 12:26:50 +00:00
mattrussell36 12a799a2fd chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-16 12:08:50 +00:00
mattrussell36 e91a37684a chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-16 06:06:37 +00:00
mattrussell36 b4a0e74457 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-16 00:12:40 +00:00
mattrussell36 11ba5e733e chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-15 18:07:24 +00:00
mattrussell36 315c463eec chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-15 12:06:07 +00:00
mattrussell36 62bfbd6822 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-15 06:07:31 +00:00
mattrussell36 290c2e3d42 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-15 00:10:47 +00:00
mattrussell36 c67daf885c chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-14 18:08:19 +00:00
mattrussell36 c3944128eb chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-14 12:08:40 +00:00
mattrussell36 c63d2a9bc6 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-14 06:06:06 +00:00
mattrussell36 e00998f9e3 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-14 00:10:11 +00:00
mattrussell36 61a5098776 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-13 18:06:05 +00:00
Matthew Russell 9203c81084 chore: fix governance app link for mirror env 2023-01-13 08:17:56 -08:00
m.rayandMatthew Russell 8864696783 chore: merge release/testnet back in develop (#2613)
* chore: add mirror config for trading

* chore: fix url for mainnet mirror in network config

* fix: remove link if no market id

Co-authored-by: Matthew Russell <mattrussell36@gmail.com>
2023-01-13 14:10:31 +00:00
mattrussell36 99d338f50a chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-13 12:06:53 +00:00
macqbat 2b28ff6c18 chore: update fills tab - add tooltip with fees breakdown (#2606)
* chore: update fills tab - add tooltip with fees breakdown

* chore: update fills tab - fix failing unit test

* chore: update fills tab - add unit test

* chore: update fills tab - adjust int test
2023-01-13 10:44:01 +00:00
Edd 6d3795f1f4 build(explorer): checkout mirror conf from mirror release branch 2023-01-13 10:21:56 +00:00
mattrussell36 c0b84a88d3 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-13 06:07:37 +00:00
mattrussell36 5b0d799a00 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-13 00:11:40 +00:00
Matthew Russell 9e6ecbc558 chore: fix url for mainnet mirror in network config 2023-01-12 13:03:08 -08:00
mattrussell36 c3de7f12f0 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-12 18:06:47 +00:00
Joe Tsang 473fdf8466 test(2578): download proposal json (#2596)
* chore: add test for downloading proposal json

* chore: remove seconds from json file names
2023-01-12 14:36:09 +00:00
Sam Keen 47c0ec01eb feat(2601): token homepage proposals should have their width halved on larger breakpoints (#2603) 2023-01-12 14:18:17 +00:00
mattrussell36 6410cb54b6 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-12 12:06:50 +00:00
Dexter EdwardsandJoe b8ff3d3050 feat(2093): token sub nav (#2549)
* feat: implement subnav using exisitng DD component

* chore: make nav as per design

* chore: fix conflicts

* style: make css for trigger match designs

* chore: add border to subnav card

* chore: reogranise files

* chore: remove unused imports

* fix: minor rendering errors

* test: add first tests

* chore: fix failing tests from nav update

* test: add unit tests for nav

* style: lint

* style: make navbar theme work properly

* style: lint

* chore: remove unnecessary click on header

* fix: move route config to ts only file

* test: tidy up test logic

* feat: add nav drop down to ui toolkit

* fix: broken routing in places

* style: lint

Co-authored-by: Joe <joe@vega.xyz>
2023-01-12 11:45:22 +00:00
Dexter d474a502a8 ci: force build 2023-01-12 11:20:31 +00:00
macqbat 06e1b3663d chore: volume in chart enabled by default (#2577)
* chore: volume in chart enabled by default

* chore: volume in chart enabled by default - add unit test
2023-01-12 11:49:57 +01:00
Sam Keen 38ff2c24e4 fix(2590): download JSON for some proposal types not working if proposal terms is empty (#2591) 2023-01-12 09:40:31 +00:00
mattrussell36 2689bbdcd2 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-12 06:07:49 +00:00
mattrussell36 c7b4465adf chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-12 00:12:29 +00:00
mattrussell36 3f6913ab39 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-11 18:08:00 +00:00
m.ray 31ffa306eb fix(#2554): close out formatting (#2584)
* fix(#2530): fix use order close out - formatting to be done in component

* fix: format number in console-lite
2023-01-11 17:10:35 +00:00
Radosław Szpiech 13ab03c459 chore: remove liquidity-provision-dashobard-e2e as it is not maintained (#2589) 2023-01-11 18:02:16 +01:00
Radosław Szpiech dd2e3a6556 chore: remove stats and stats-e2e by burning them to the scorched ground (#2586) 2023-01-11 17:45:08 +01:00
Bartłomiej Głownia 4608683bde feat(2408): trading data grid snags (#2513)
* feat: trading data grid snags

* feat: fix e2e tests, fix use order list data avoid rerender condition
2023-01-11 15:43:52 +01:00
mattrussell36 1f96ccea68 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-11 12:08:56 +00:00
mattrussell36 c055be1146 chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-11 06:06:35 +00:00
mattrussell36 a316eaae9d chore: update tranches
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2023-01-11 00:12:29 +00:00
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
862 changed files with 21123 additions and 17669 deletions
@@ -1,6 +1,18 @@
outputs:
token:
description: 'api-token of wallet'
value: ${{ steps.generate-api-token.outputs.api-token }}
runs:
using: 'composite'
steps:
- name: Vegacapsule version
shell: bash
run: vegacapsule version
- name: Vega wallet version
shell: bash
run: vega wallet software version
- name: Start nomad
shell: bash
run: vegacapsule nomad &
@@ -8,3 +20,32 @@ runs:
- name: Bootstrap network
shell: bash
run: vegacapsule network bootstrap --config-path=./frontend-monorepo/vegacapsule/config.hcl --force
- name: Initialize wallet
shell: bash
run: vega wallet init -f --home ~/.vegacapsule/testnet/wallet
- name: Import wallet
shell: bash
run: vega wallet import -w capsule_wallet --recovery-phrase-file ./frontend-monorepo/vegacapsule/recovery -p ./frontend-monorepo/vegacapsule/passphrase --home ~/.vegacapsule/testnet/wallet
- name: Generate second public key
shell: bash
run: vega wallet key generate -w capsule_wallet -p ./frontend-monorepo/vegacapsule/passphrase --home ~/.vegacapsule/testnet/wallet
- name: Import network
shell: bash
run: vega wallet network import --force --from-file ./frontend-monorepo/vegacapsule/wallet-config.toml --home ~/.vegacapsule/testnet/wallet
- name: Init api-token
shell: bash
run: vega wallet api-token init --home ~/.vegacapsule/testnet/wallet --passphrase-file ./frontend-monorepo/vegacapsule/passphrase
- name: Generate api-token
id: generate-api-token
shell: bash
run: echo api-token=$(vega wallet api-token generate --wallet-name capsule_wallet --tokens-passphrase-file ./frontend-monorepo/vegacapsule/passphrase --wallet-passphrase-file ./frontend-monorepo/vegacapsule/passphrase --home ~/.vegacapsule/testnet/wallet | grep -Eo '[a-zA-Z0-9]{64}') >> $GITHUB_OUTPUT
- name: Start service using capsule network
shell: bash
run: vega wallet service run -n DV --load-tokens --tokens-passphrase-file ./frontend-monorepo/vegacapsule/passphrase --no-version-check --automatic-consent --home ~/.vegacapsule/testnet/wallet &
@@ -1,38 +0,0 @@
inputs:
passphrase:
description: 'Wallet password'
outputs:
token:
description: 'api-token of wallet'
value: ${{ steps.generate-api-token.outputs.api-token }}
runs:
using: 'composite'
steps:
- name: Initialize wallet
shell: bash
run: vega wallet init -f --home ~/.vegacapsule/testnet/wallet
- name: Import wallet
shell: bash
run: vega wallet import -w capsule_wallet --recovery-phrase-file ./frontend-monorepo/vegacapsule/recovery -p ./frontend-monorepo/vegacapsule/passphrase --home ~/.vegacapsule/testnet/wallet
- name: Generate second public key
shell: bash
run: vega wallet key generate -w capsule_wallet -p ./frontend-monorepo/vegacapsule/passphrase --home ~/.vegacapsule/testnet/wallet
- name: Import network
shell: bash
run: vega wallet network import --force --from-file ./frontend-monorepo/vegacapsule/wallet-config.toml --home ~/.vegacapsule/testnet/wallet
- name: Init api-token
shell: bash
run: vega wallet api-token init --home ~/.vegacapsule/testnet/wallet --passphrase-file ./frontend-monorepo/vegacapsule/passphrase
- name: Generate api-token
id: generate-api-token
shell: bash
run: echo api-token=$(vega wallet api-token generate --wallet-name capsule_wallet --tokens-passphrase-file ./frontend-monorepo/vegacapsule/passphrase --wallet-passphrase-file ./frontend-monorepo/vegacapsule/passphrase --home ~/.vegacapsule/testnet/wallet | grep -Eo '[a-zA-Z0-9]{64}') >> $GITHUB_OUTPUT
- name: Start service using capsule network
shell: bash
run: vega wallet service run -n DV --load-tokens --tokens-passphrase-file ./frontend-monorepo/vegacapsule/passphrase --no-version-check --automatic-consent --home ~/.vegacapsule/testnet/wallet &
@@ -1,48 +0,0 @@
inputs:
recovery:
description: 'Recovery phrase'
passphrase:
description: 'Wallet password'
outputs:
token:
description: 'api-token of wallet'
value: ${{ steps.generate-api-token.outputs.api-token }}
runs:
using: 'composite'
steps:
- name: Create passphrase
shell: bash
run: echo "${{ inputs.passphrase }}" > ./passphrase
- name: Create recovery
shell: bash
run: echo "${{ inputs.recovery }}" > ./recovery
- name: Initialize wallet
shell: bash
run: vega wallet init -f --home ~/.vegacapsule/testnet/wallet
- name: Import wallet
shell: bash
run: vega wallet import -w UI_Trading_Test --recovery-phrase-file ./recovery -p ./passphrase --home ~/.vegacapsule/testnet/wallet
- name: Create public key 2
shell: bash
run: vega wallet key generate -w UI_Trading_Test -p ./passphrase --home ~/.vegacapsule/testnet/wallet
- name: Import network
shell: bash
run: vega wallet network import --from-url="https://raw.githubusercontent.com/vegaprotocol/networks-internal/main/stagnet3/vegawallet-stagnet3.toml" --force --home ~/.vegacapsule/testnet/wallet
- name: Init api-token
shell: bash
run: vega wallet api-token init --home ~/.vegacapsule/testnet/wallet --passphrase-file passphrase
- name: Generate api-token
id: generate-api-token
shell: bash
run: echo api-token=$(vega wallet api-token generate --wallet-name UI_Trading_Test --tokens-passphrase-file passphrase --wallet-passphrase-file passphrase --home ~/.vegacapsule/testnet/wallet | grep -Eo '[a-zA-Z0-9]{64}') >> $GITHUB_OUTPUT
- name: Start service using stagnet3 network
shell: bash
run: vega wallet service run -n stagnet3 --load-tokens --tokens-passphrase-file passphrase --no-version-check --automatic-consent --home ~/.vegacapsule/testnet/wallet &
@@ -1,52 +0,0 @@
name: Cypress tests -- manual trigger
# This workflow runs the frontend tests against chosen branch
on:
workflow_dispatch:
inputs:
project:
description: 'Project'
required: true
type: choice
options:
- console-lite-e2e
- explorer-e2e
- liquidity-provision-dashboard-e2e
- stats-e2e
- token-e2e
- trading-e2e
tags:
description: 'Test tags to run'
required: true
type: string
default: '@smoke, @regression, @slow'
skip-nx-cache:
description: 'Add --skip-nx-cache to cypress test'
required: false
type: boolean
default: false
jobs:
manual:
name: Run Cypress tests -- manual trigger
runs-on: ubuntu-latest
steps:
- name: Set tags
run: echo TAGS="--env.grepTags '[ ${{ github.event.inputs.tags }} ]'" >> $GITHUB_ENV
- name: Set --skip-nx-cache flag
if: ${{ github.event.inputs.skip-nx-cache == 'true' }}
run: echo SKIP_NX_CACHE="--skip-nx-cache" >> $GITHUB_ENV
outputs:
skip-cache: ${{env.SKIP_NX_CACHE}}
tags: ${{env.TAGS}}
dispatch:
needs: manual
uses: ./.github/workflows/tests-dispatcher.yml
secrets: inherit
with:
project: ${{ inputs.project }}
skip-cache: ${{needs.manual.outputs.skip-cache}}
tags: ${{needs.manual.outputs.tags}}
@@ -1,17 +0,0 @@
name: Cypress tests -- night run
# This workflow runs the frontend tests against latest develop of the core to preempt breaking changes
on:
schedule:
- cron: '0 4 * * *'
workflow_dispatch:
jobs:
nightly:
uses: ./.github/workflows/tests-dispatcher.yml
secrets: inherit
with:
project: '[console-lite-e2e, explorer-e2e, liquidity-provision-dashboard-e2e, stats-e2e, token-e2e, trading-e2e]'
tags: --env.grepTags '[ @smoke, @regression, @slow ]'
night-run: true
-61
View File
@@ -1,61 +0,0 @@
name: Cypress tests - PR
on:
push:
branches:
- develop
- main
pull_request:
types:
- opened
- reopened
- synchronize
- ready_for_review
jobs:
pr:
runs-on: ubuntu-latest
steps:
# Checkout front ends
- name: Checkout frontend mono repo
uses: actions/checkout@v2
with:
fetch-depth: 0
path: './frontend-monorepo'
# Restore node_modules from cache if possible
- name: Restore node_modules from cache
uses: actions/cache@v3
with:
path: |
frontend-monorepo/node_modules
/home/runner/.cache/Cypress
key: node_modules_cypress-${{ hashFiles('frontend-monorepo/yarn.lock') }}
# Install frontend dependencies
- name: Install root dependencies
run: yarn install --frozen-lockfile
working-directory: frontend-monorepo
# Check SHAs
- name: Derive appropriate SHAs for base and head for `nx affected` commands
uses: nrwl/nx-set-shas@v2
with:
working-directory: frontend-monorepo
main-branch-name: ${{ github.base_ref || github.ref_name }}
set-environment-variables-for-job: true
# See affected projects
- name: See affected apps
run: echo AFFECTED=$(yarn nx print-affected --base=${{ env.NX_BASE }} --head=${{ env.NX_HEAD }} --select=projects) >> $GITHUB_ENV
working-directory: frontend-monorepo
outputs:
projects: ${{ env.AFFECTED }}
dispatch:
needs: pr
uses: ./.github/workflows/tests-dispatcher.yml
secrets: inherit
with:
project: ${{ needs.pr.outputs.projects }}
tags: "--env.grepTags='[ @smoke, @regression ]'"
@@ -1,69 +0,0 @@
name: Cypress - console-lite
on:
workflow_call:
inputs:
trigger:
required: true
type: string
default: 'false'
skip-cache:
required: false
type: string
tags:
required: false
type: string
jobs:
console-lite-e2e:
if: ${{ inputs.trigger == 'true' }}
runs-on: self-hosted
steps:
- name: Vega version
run: vega version
# Checkout front ends
- name: Checkout frontend mono repo
uses: actions/checkout@v3
with:
fetch-depth: 0
path: './frontend-monorepo'
# Restore node_modules from cache if possible
- name: Restore node_modules from cache
uses: actions/cache@v3
with:
path: |
frontend-monorepo/node_modules
/home/runner/.cache/Cypress
key: node_modules_cypress-${{ hashFiles('frontend-monorepo/yarn.lock') }}
# Install frontend dependencies
- name: Install root dependencies
run: yarn install --frozen-lockfile
working-directory: frontend-monorepo
######
## Setup a Vega wallet for our user
######
- name: Set up Vegawallet
id: setup-vega
uses: ./frontend-monorepo/.github/actions/setup-vegawallet
with:
recovery: ${{ secrets.TRADING_TEST_VEGA_WALLET_RECOVERY }}
passphrase: ${{ secrets.CYPRESS_TRADING_TEST_VEGA_WALLET_PASSPHRASE }}
# To make sure that all Cypress binaries are installed properly
- name: Install cypress bins
run: yarn cypress install
working-directory: frontend-monorepo
- name: Run Cypress tests
run: npx nx run console-lite-e2e:e2e ${{ inputs.skip-cache }} --record --key ${{ secrets.CYPRESS_RECORD_KEY }} --browser chrome ${{ inputs.tags }}
working-directory: frontend-monorepo
env:
CYPRESS_TRADING_TEST_VEGA_WALLET_PASSPHRASE: ${{ secrets.CYPRESS_TRADING_TEST_VEGA_WALLET_PASSPHRASE }}
CYPRESS_SLACK_WEBHOOK: ${{ secrets.CYPRESS_SLACK_WEBHOOK }}
CYPRESS_ETH_WALLET_MNEMONIC: ${{ secrets.CYPRESS_ETH_WALLET_MNEMONIC }}
CYPRESS_VEGA_WALLET_API_TOKEN: ${{ steps.setup-vega.outputs.token }}
-106
View File
@@ -1,106 +0,0 @@
name: Cypress - explorer
on:
workflow_call:
inputs:
trigger:
required: true
type: string
default: 'false'
skip-cache:
required: false
type: string
tags:
required: false
type: string
night-run:
required: false
type: boolean
default: false
jobs:
explorer-e2e:
if: ${{ inputs.trigger == 'true' }}
runs-on: self-hosted
timeout-minutes: 30
steps:
- name: Vega version
run: vega version
- name: Vegacapsule version
run: vegacapsule version
# Checkout front ends
- name: Checkout frontend mono repo
uses: actions/checkout@v3
with:
fetch-depth: 0
path: './frontend-monorepo'
# Restore node_modules from cache if possible
- name: Restore node_modules from cache
uses: actions/cache@v3
with:
path: |
frontend-monorepo/node_modules
/home/runner/.cache/Cypress
key: node_modules_cypress-${{ hashFiles('frontend-monorepo/yarn.lock') }}
# Install frontend dependencies
- name: Install root dependencies
run: yarn install --frozen-lockfile
working-directory: frontend-monorepo
#######
## Build and run Vegacapsule network
#######
- name: Build and run Vegacapsule network
uses: ./frontend-monorepo/.github/actions/run-vegacapsule
######
## Setup a Vega wallet for our user
######
- name: Set up Vegawallet for docker
id: setup-vega
uses: ./frontend-monorepo/.github/actions/setup-vegawallet-docker
with:
passphrase: ${{ secrets.CYPRESS_TRADING_TEST_VEGA_WALLET_PASSPHRASE }}
######
## Run some tests
######
# To make sure that all Cypress binaries are installed properly
- name: Install cypress bins
run: yarn cypress install
working-directory: frontend-monorepo
- name: Run Cypress tests
run: npx nx run explorer-e2e:e2e ${{ inputs.skip-cache }} --record --key ${{ secrets.CYPRESS_RECORD_KEY }} --browser chrome ${{ inputs.tags }}
working-directory: frontend-monorepo
env:
CYPRESS_TRADING_TEST_VEGA_WALLET_PASSPHRASE: ${{ secrets.CYPRESS_TRADING_TEST_VEGA_WALLET_PASSPHRASE }}
CYPRESS_SLACK_WEBHOOK: ${{ secrets.CYPRESS_SLACK_WEBHOOK }}
CYPRESS_ETH_WALLET_MNEMONIC: ${{ secrets.CYPRESS_ETH_WALLET_MNEMONIC }}
CYPRESS_NIGHTLY_RUN: ${{ inputs.night-run }}
CYPRESS_VEGA_WALLET_API_TOKEN: ${{ steps.setup-vega.outputs.token }}
######
## Upload logs
######
# Artifact path is not valid: /ganache-1/capsule-logscolletor.stderr-2022-12-22T10:20:30Z.log. Contains the following character: Colon :
- name: Rename files to allow archive
if: ${{ always() }}
run: |
while read -r file; do
mv "${file}" "$(echo ${file} | sed 's|:|-|g')"
done< <(find /home/runner/.vegacapsule/testnet/logs -type f)
- uses: actions/upload-artifact@v2
if: ${{ always() }}
with:
name: logs
path: /home/runner/.vegacapsule/testnet/logs
@@ -1,47 +0,0 @@
name: Cypress - liquidity provision dashboard
on:
workflow_call:
inputs:
trigger:
required: true
type: string
default: 'false'
jobs:
liquidity-provision-dashboard-e2e:
timeout-minutes: 10
if: ${{ inputs.trigger == 'true' }}
runs-on: self-hosted
steps:
# Checkout front ends
- name: Checkout frontend mono repo
uses: actions/checkout@v3
with:
fetch-depth: 0
path: './frontend-monorepo'
# Restore node_modules from cache if possible
- name: Restore node_modules from cache
uses: actions/cache@v3
with:
path: |
frontend-monorepo/node_modules
/home/runner/.cache/Cypress
key: node_modules_cypress-${{ hashFiles('frontend-monorepo/yarn.lock') }}
# Install frontend dependencies
- name: Install root dependencies
run: yarn install --frozen-lockfile
working-directory: frontend-monorepo
# To make sure that all Cypress binaries are installed properly
- name: Install cypress bins
run: yarn cypress install
working-directory: frontend-monorepo
- name: Run Cypress tests
run: npx nx run liquidity-provision-dashboard-e2e:e2e --record --key ${{ secrets.CYPRESS_RECORD_KEY }} --browser chrome
working-directory: frontend-monorepo
env:
CYPRESS_SLACK_WEBHOOK: ${{ secrets.CYPRESS_SLACK_WEBHOOK }}
@@ -0,0 +1,33 @@
name: Cypress tests -- manual trigger
# This workflow runs the frontend tests against chosen branch
on:
workflow_dispatch:
inputs:
project:
description: 'Project'
required: true
type: choice
options:
- explorer-e2e
- token-e2e
- trading-e2e
tags:
description: 'Test tags to run'
required: true
type: string
default: '@smoke @regression @slow'
skip-nx-cache:
description: 'Skip NX cache'
required: false
type: boolean
default: false
jobs:
manual:
uses: ./.github/workflows/cypress-run.yml
secrets: inherit
with:
projects: '["${{inputs.project}}"]'
skip-cache: ${{inputs.skip-nx-cache}}
tags: ${{inputs.tags}}
+14
View File
@@ -0,0 +1,14 @@
name: Cypress tests -- night run
on:
schedule:
- cron: '0 4 * * *'
workflow_dispatch:
jobs:
nightly:
uses: ./.github/workflows/cypress-run.yml
secrets: inherit
with:
projects: '["explorer-e2e","token-e2e","trading-e2e"]'
tags: '@smoke @regression @slow'
+78
View File
@@ -0,0 +1,78 @@
name: Cypress tests - PR
on:
push:
branches:
- develop
- main
pull_request:
types:
- opened
- reopened
- synchronize
- ready_for_review
jobs:
pr:
runs-on: ubuntu-latest
steps:
- name: Checkout frontend mono repo
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Setup node
uses: actions/setup-node@v3
- name: Remove package.json & yarn.lock to avoid installing everything
run: rm package.json yarn.lock
- name: Install nx
run: yarn add nx
# Check SHAs
- name: Derive appropriate SHAs for base and head for `nx affected` commands
uses: nrwl/nx-set-shas@v2
with:
main-branch-name: ${{ github.base_ref || github.ref_name }}
set-environment-variables-for-job: true
# See affected apps
- name: See affected apps
run: |
affected=$(yarn nx print-affected --base=${{ env.NX_BASE }} --head=${{ env.NX_HEAD }} --select=projects)
echo -n "Affected projects: $affected"
projects=""
if [[ $affected == *"token"* ]]; then projects+='"token-e2e" '; fi
if [[ $affected == *"trading"* ]]; then projects+='"trading-e2e" '; fi
if [[ $affected == *"explorer"* ]]; then projects+='"explorer-e2e" '; fi
if [[ -z "$projects" ]]; then projects+='"token-e2e" "trading-e2e" "explorer-e2e" '; fi
projects=${projects%?}
projects=[${projects// /,}]
echo PROJECTS=$projects >> $GITHUB_ENV
outputs:
projects: ${{ env.PROJECTS }}
run:
needs: pr
if: ${{ needs.pr.outputs.projects != '[]' }}
uses: ./.github/workflows/cypress-run.yml
secrets: inherit
with:
projects: ${{ needs.pr.outputs.projects }}
tags: '@smoke @regression'
# Report single result at the end, to avoid mess with required checks in PR
result:
if: ${{ always() }}
needs: run
runs-on: ubuntu-latest
name: Cypress result
steps:
- run: |
result="${{ needs.run.result }}"
if [[ $result == "success" || $result == "skipped" ]]; then
exit 0
else
exit 1
fi
@@ -1,30 +1,29 @@
name: Cypress - token
on:
workflow_call:
inputs:
trigger:
projects:
required: true
type: string
default: 'false'
skip-cache:
required: false
type: string
type: boolean
tags:
required: false
type: string
jobs:
token-e2e:
if: ${{ inputs.trigger == 'true' }}
runs-on: self-hosted
timeout-minutes: 60
e2e:
strategy:
fail-fast: false
matrix:
project: ${{ fromJSON(inputs.projects) }}
runs-on: self-hosted-runner
timeout-minutes: 30
steps:
- name: Vega version
run: vega version
- name: Vegacapsule version
run: vegacapsule version
# Checks if skip cache was requested
- name: Set skip-nx-cache flag
if: ${{ inputs.skip-cache == true }}
run: echo "SKIP_CACHE=--skip-nx-cache" >> $GITHUB_ENV
# Checkout front ends
- name: Checkout frontend mono repo
@@ -40,47 +39,37 @@ jobs:
path: |
frontend-monorepo/node_modules
/home/runner/.cache/Cypress
key: node_modules_cypress-${{ hashFiles('frontend-monorepo/yarn.lock') }}
key: node_modules_cypress-${{ hashFiles('frontend-monorepo/yarn.lock', 'frontend-monorepo/package.json') }}
# Install frontend dependencies
- name: Install root dependencies
run: yarn install --frozen-lockfile
working-directory: frontend-monorepo
#######
## Build and run Vegacapsule network
#######
- name: Build and run Vegacapsule network
uses: ./frontend-monorepo/.github/actions/run-vegacapsule
# Make sure that all Cypress binaries are installed properly
- name: Install cypress bins
run: yarn cypress install
working-directory: frontend-monorepo
######
## Setup a Vega wallet for our user
## Setup Vegacapsule and Vega wallet
######
- name: Set up Vegawallet for docker
- name: Run Vegacapsule network and Vega wallet
id: setup-vega
uses: ./frontend-monorepo/.github/actions/setup-vegawallet-docker
with:
passphrase: ${{ secrets.CYPRESS_TRADING_TEST_VEGA_WALLET_PASSPHRASE }}
uses: ./frontend-monorepo/.github/actions/run-vegacapsule
######
## Run some tests
######
# To make sure that all Cypress binaries are installed properly
- name: Install cypress bins
run: yarn cypress install
working-directory: frontend-monorepo
- name: Run Cypress tests
run: npx nx run token-e2e:e2e ${{ inputs.skip-cache }} --record --key ${{ secrets.CYPRESS_RECORD_KEY }} --browser chrome ${{ inputs.tags }}
run: yarn nx run ${{ matrix.project }}:e2e ${{ env.SKIP_CACHE }} --record --key ${{ secrets.CYPRESS_RECORD_KEY }} --browser chrome
working-directory: frontend-monorepo
env:
CYPRESS_TRADING_TEST_VEGA_WALLET_PASSPHRASE: ${{ secrets.CYPRESS_TRADING_TEST_VEGA_WALLET_PASSPHRASE }}
CYPRESS_SLACK_WEBHOOK: ${{ secrets.CYPRESS_SLACK_WEBHOOK }}
CYPRESS_ETH_WALLET_MNEMONIC: ${{ secrets.CYPRESS_ETH_WALLET_MNEMONIC }}
CYPRESS_VEGA_WALLET_API_TOKEN: ${{ steps.setup-vega.outputs.token }}
CYPRESS_grepTags: ${{ inputs.tags }}
######
## Upload logs
@@ -94,8 +83,8 @@ jobs:
mv "${file}" "$(echo ${file} | sed 's|:|-|g')"
done< <(find /home/runner/.vegacapsule/testnet/logs -type f)
- uses: actions/upload-artifact@v2
- uses: actions/upload-artifact@v3
if: ${{ always() }}
with:
name: logs
name: logs-${{ matrix.project }}
path: /home/runner/.vegacapsule/testnet/logs
-47
View File
@@ -1,47 +0,0 @@
name: Cypress - stats
on:
workflow_call:
inputs:
trigger:
required: true
type: string
default: 'false'
jobs:
stats-e2e:
runs-on: self-hosted
if: ${{ inputs.trigger == 'true' }}
timeout-minutes: 10
steps:
# Checkout front ends
- name: Checkout frontend mono repo
uses: actions/checkout@v3
with:
fetch-depth: 0
path: './frontend-monorepo'
# Restore node_modules from cache if possible
- name: Restore node_modules from cache
uses: actions/cache@v3
with:
path: |
frontend-monorepo/node_modules
/home/runner/.cache/Cypress
key: node_modules_cypress-${{ hashFiles('frontend-monorepo/yarn.lock') }}
# Install frontend dependencies
- name: Install root dependencies
run: yarn install --frozen-lockfile
working-directory: frontend-monorepo
# To make sure that all Cypress binaries are installed properly
- name: Install cypress bins
run: yarn cypress install
working-directory: frontend-monorepo
- name: Run Cypress tests
run: npx nx run stats-e2e:e2e --record --key ${{ secrets.CYPRESS_RECORD_KEY }} --browser chrome
working-directory: frontend-monorepo
env:
CYPRESS_SLACK_WEBHOOK: ${{ secrets.CYPRESS_SLACK_WEBHOOK }}
-70
View File
@@ -1,70 +0,0 @@
name: Cypress - trading
on:
workflow_call:
inputs:
trigger:
required: true
type: string
default: 'false'
skip-cache:
required: false
type: string
tags:
required: false
type: string
jobs:
trading-e2e:
if: ${{ inputs.trigger == 'true' }}
timeout-minutes: 30
runs-on: self-hosted
steps:
- name: Vega version
run: vega version
# Checkout front ends
- name: Checkout frontend mono repo
uses: actions/checkout@v3
with:
fetch-depth: 0
path: './frontend-monorepo'
# Restore node_modules from cache if possible
- name: Restore node_modules from cache
uses: actions/cache@v3
with:
path: |
frontend-monorepo/node_modules
/home/runner/.cache/Cypress
key: node_modules_cypress-${{ hashFiles('frontend-monorepo/yarn.lock') }}
# Install frontend dependencies
- name: Install root dependencies
run: yarn install --frozen-lockfile
working-directory: frontend-monorepo
######
## Setup a Vega wallet for our user
######
- name: Set up Vegawallet
id: setup-vega
uses: ./frontend-monorepo/.github/actions/setup-vegawallet
with:
recovery: ${{ secrets.TRADING_TEST_VEGA_WALLET_RECOVERY }}
passphrase: ${{ secrets.CYPRESS_TRADING_TEST_VEGA_WALLET_PASSPHRASE }}
# To make sure that all Cypress binaries are installed properly
- name: Install cypress bins
run: yarn cypress install
working-directory: frontend-monorepo
- name: Run Cypress tests
run: npx nx run trading-e2e:e2e ${{ inputs.skip-cache }} --record --key ${{ secrets.CYPRESS_RECORD_KEY }} --browser chrome ${{ inputs.tags }}
working-directory: frontend-monorepo
env:
CYPRESS_TRADING_TEST_VEGA_WALLET_PASSPHRASE: ${{ secrets.CYPRESS_TRADING_TEST_VEGA_WALLET_PASSPHRASE }}
CYPRESS_SLACK_WEBHOOK: ${{ secrets.CYPRESS_SLACK_WEBHOOK }}
CYPRESS_ETH_WALLET_MNEMONIC: ${{ secrets.CYPRESS_ETH_WALLET_MNEMONIC }}
CYPRESS_VEGA_WALLET_API_TOKEN: ${{ steps.setup-vega.outputs.token }}
-61
View File
@@ -1,61 +0,0 @@
on:
workflow_call:
inputs:
project:
required: true
type: string
skip-cache:
required: false
type: string
tags:
required: false
type: string
night-run:
required: false
type: boolean
jobs:
run-console-lite-e2e:
uses: ./.github/workflows/cypress-console-lite-e2e.yml
secrets: inherit
with:
trigger: ${{ contains(inputs.project, 'console-lite-e2e') || contains(inputs.project, 'console-lite') }}
skip-cache: ${{ inputs.skip-cache }}
tags: ${{ inputs.tags }}
run-explorer-e2e:
uses: ./.github/workflows/cypress-explorer-e2e.yml
secrets: inherit
with:
trigger: ${{ contains(inputs.project, 'explorer-e2e') || contains(inputs.project, 'explorer') }}
skip-cache: ${{ inputs.skip-cache }}
tags: ${{ inputs.tags }}
night-run: ${{ inputs.night-run }}
run-liquidity-e2e:
uses: ./.github/workflows/cypress-liquidity-provision-dashboard-e2e.yml
secrets: inherit
with:
trigger: ${{ contains(inputs.project, 'liquidity-provision-dashboard-e2e') || contains(inputs.project, 'liquidity-provision-dashboard') }}
run-stats-e2e:
uses: ./.github/workflows/cypress-stats-e2e.yml
secrets: inherit
with:
trigger: ${{ contains(inputs.project, 'stats-e2e') || contains(inputs.project, 'stats') }}
run-token-e2e:
uses: ./.github/workflows/cypress-token-e2e.yml
secrets: inherit
with:
trigger: ${{ contains(inputs.project, 'token-e2e') || contains(inputs.project, 'token') }}
skip-cache: ${{ inputs.skip-cache }}
tags: ${{ inputs.tags }}
run-trading-e2e:
uses: ./.github/workflows/cypress-trading-e2e.yml
secrets: inherit
with:
trigger: ${{ contains(inputs.project, 'trading-e2e') || contains(inputs.project, 'trading') }}
skip-cache: ${{ inputs.skip-cache }}
tags: ${{ inputs.tags }}
-4
View File
@@ -22,10 +22,6 @@ The utility dApp for interacting with the Vega token and using its' utility. Thi
The block explorer for the Vega network, showing details of raw chain states and the state of markets on the Vega network.
### [Stats](./apps/stats)
An application for the status of the Vega network. Showing block height and other network activity.
### [Static](./apps/static)
Hosting for static content being shared across apps, for example fonts.
-10
View File
@@ -1,10 +0,0 @@
# App configuration variables
NX_VEGA_CONFIG_URL=https://static.vega.xyz/assets/stagnet3-network.json
NX_VEGA_URL=https://api.stagnet3.vega.xyz/graphql
NX_VEGA_ENV=STAGNET3
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_VEGA_EXPLORER_URL=https://stagnet3.explorer.vega.xyz
NX_VEGA_WALLET_URL=http://localhost:1789
CYPRESS_VEGA_ENV=STAGNET3
CYPRESS_VEGA_WALLET_API_TOKEN=
-10
View File
@@ -1,10 +0,0 @@
{
"extends": ["plugin:cypress/recommended", "../../.eslintrc.json"],
"ignorePatterns": ["!**/*"],
"overrides": [
{
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
"rules": {}
}
]
}
-45
View File
@@ -1,45 +0,0 @@
const { defineConfig } = require('cypress');
module.exports = defineConfig({
projectId: 'et4snf',
e2e: {
setupNodeEvents(on, config) {
require('@cypress/grep/src/plugin')(config);
return config;
},
baseUrl: 'http://localhost:4200',
fileServerFolder: '.',
fixturesFolder: false,
specPattern: './src/integration/*.ts',
excludeSpecPattern: '**/*.js',
modifyObstructiveCode: false,
supportFile: './src/support/index.js',
video: false,
videoUploadOnPasses: false,
videosFolder: '../../dist/cypress/apps/console-lite-e2e/videos',
screenshotsFolder: '../../dist/cypress/apps/console-lite-e2e/screenshots',
chromeWebSecurity: false,
viewportWidth: 1440,
viewportHeight: 900,
},
env: {
ETHEREUM_PROVIDER_URL:
'https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8',
VEGA_PUBLIC_KEY:
'47836c253520d2661bf5bed6339c0de08fd02cf5d4db0efee3b4373f20c7d278',
VEGA_PUBLIC_KEY2:
'1a18cdcaaa4f44a57b35a4e9b77e0701c17a476f2b407620f8c17371740cf2e4',
TRUNCATED_VEGA_PUBLIC_KEY: '47836c…c7d278',
TRUNCATED_VEGA_PUBLIC_KEY2: '1a18cd…0cf2e4',
ETHEREUM_WALLET_ADDRESS: '0x265Cc6d39a1B53d0d92068443009eE7410807158',
ETHERSCAN_URL: 'https://sepolia.etherscan.io',
tsConfig: 'tsconfig.json',
TAGS: 'not @todo and not @ignore and not @manual',
TRADING_TEST_VEGA_WALLET_PASSPHRASE: '123',
ETH_WALLET_MNEMONIC:
'ugly gallery notice network true range brave clarify flat logic someone chunk',
grepTags: '@regression @smoke @slow',
grepFilterSpecs: true,
grepOmitFiltered: true,
},
});
-1
View File
@@ -1 +0,0 @@
declare module '*.scss';
-20
View File
@@ -1,20 +0,0 @@
/// <reference types="cypress" />
declare namespace Cypress {
// specify additional properties in the TestConfig object
// in our case we will add "tags" property
interface SuiteConfigOverrides {
/**
* List of tags for this test
* @example a single tag
* it('logs in', { tags: '@smoke' }, () => { ... })
* @example multiple tags
* it('works', { tags: ['@smoke', '@slow'] }, () => { ... })
*/
tags?: string | string[];
}
interface Cypress {
grep?: (grep?: string, tags?: string, burn?: string) => void;
}
}
-35
View File
@@ -1,35 +0,0 @@
{
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "apps/console-lite-e2e/src",
"projectType": "application",
"targets": {
"e2e": {
"executor": "@nrwl/cypress:cypress",
"options": {
"cypressConfig": "apps/console-lite-e2e/cypress.config.js",
"devServerTarget": "console-lite:serve"
},
"configurations": {
"production": {
"devServerTarget": "console-lite:serve:production"
}
}
},
"lint": {
"executor": "@nrwl/linter:eslint",
"outputs": ["{options.outputFile}"],
"options": {
"lintFilePatterns": ["apps/console-lite-e2e/**/*.{js,ts}"]
}
},
"build": {
"executor": "@nrwl/workspace:run-commands",
"outputs": [],
"options": {
"command": "yarn tsc --project ./apps/console-lite-e2e/"
}
}
},
"tags": [],
"implicitDependencies": ["console-lite"]
}
@@ -1,10 +0,0 @@
describe('simple trading app', { tags: '@smoke' }, () => {
beforeEach(() => {
cy.mockConsole();
cy.visit('/');
});
it('render', () => {
cy.get('#root').should('exist');
});
});
@@ -1,30 +0,0 @@
describe('console lite header', { tags: '@smoke' }, () => {
beforeEach(() => {
window.localStorage.setItem('theme', 'dark');
cy.visit('/');
});
it('logo should linked home', () => {
cy.get('span').contains('Markets').click();
cy.location('pathname').should('eq', '/markets');
cy.getByTestId('header').find('a').click();
cy.location('pathname').should('eq', '/');
});
it('theme switcher should switch theme', () => {
cy.get('#root').children().eq(0).as('Container');
cy.get('@Container').should('have.css', 'background-color', 'rgb(8, 8, 8)');
cy.getByTestId('theme-switcher').click();
cy.get('@Container').should(
'have.css',
'background-color',
'rgb(255, 255, 255)'
);
});
it('wallet connector should open a dialog', () => {
cy.get('[role="dialog"]').should('not.exist');
cy.getByTestId('connect-vega-wallet').click();
cy.get('[role="dialog"]').should('be.visible');
});
});
@@ -1,139 +0,0 @@
import { aliasGQLQuery } from '@vegaprotocol/cypress';
import type { MarketsQuery } from '@vegaprotocol/market-list';
import { marketCandlesQuery, marketsQuery } from '@vegaprotocol/mock';
describe('market list', { tags: '@smoke' }, () => {
describe('simple url', () => {
beforeEach(() => {
cy.mockConsole();
cy.visit('/markets');
});
it('selects menus', () => {
cy.get('[aria-label="Sidebar Navigation Menu"] [aria-current]').should(
'have.text',
'Markets'
);
cy.getByTestId('state-trigger').should('have.text', 'Active');
cy.get('[aria-label="Future"]').click();
cy.get('[data-testid="market-assets-menu"] a.active').should(
'have.text',
'All'
);
});
it('navigation should make possibly shortest url', () => {
cy.location('pathname').should('equal', '/markets');
cy.getByTestId('state-trigger').click();
cy.get('[role=menuitemcheckbox]').contains('All').click();
cy.location('pathname').should('equal', '/markets/all');
cy.get('[aria-label="Future"]').click();
cy.location('pathname').should('eq', '/markets/all/Future');
let asset = '';
cy.getByTestId('market-assets-menu')
.children()
.then((children) => {
if (children.length > 1) {
asset = children[1].innerText;
if (asset) {
cy.wrap(children[1]).click();
cy.location('pathname').should(
'match',
new RegExp(`/markets/all/Future/${asset}`, 'i')
);
cy.get('a').contains('All Markets').click();
cy.location('pathname').should('eq', '/markets/all');
}
}
});
cy.getByTestId('state-trigger').click();
cy.get('[role=menuitemcheckbox]').contains('Active').click();
cy.location('pathname').should('equal', '/markets');
});
});
describe('url params should select filters', () => {
beforeEach(() => {
cy.mockConsole();
});
it('suspended status', () => {
cy.visit('/markets/Suspended');
cy.getByTestId('state-trigger').should('have.text', 'Suspended');
});
it('last asset (if exists)', () => {
cy.visit('/markets');
cy.wait('@Markets').then((filters) => {
const data: MarketsQuery | undefined = filters?.response?.body?.data;
if (data?.marketsConnection?.edges.length) {
const asset =
data?.marketsConnection?.edges[0].node.tradableInstrument.instrument
.product.settlementAsset.symbol;
cy.visit(`/markets/Suspended/Future/${asset}`);
cy.getByTestId('market-assets-menu')
.find('a.active')
.should('have.text', asset);
}
});
});
it('Future product', () => {
cy.visit('/markets/Suspended/Future');
cy.getByTestId('market-products-menu')
.find('a.active')
.should('have.text', 'Future');
});
});
describe('long list of results should be handled properly', () => {
beforeEach(() => {
cy.mockConsole();
cy.viewport(1440, 900);
const market = marketsQuery().marketsConnection?.edges[0];
const edges = new Array(1000)
.fill('')
.map(() => Object.assign({}, market));
cy.mockGQL((req) => {
aliasGQLQuery(
req,
'Markets',
marketsQuery({ marketsConnection: { edges } })
);
aliasGQLQuery(req, 'MarketsCandles', marketCandlesQuery());
});
performance.mark('start-1k');
cy.visit('/markets');
cy.wait('@Markets');
});
it('handles 1000 markets', () => {
cy.get('.ag-center-cols-container', { timeout: 50000 }).then(() => {
performance.mark('end-1k');
performance.measure('load-1k', 'start-1k', 'end-1k');
const measure = performance.getEntriesByName('load-1k')[0];
expect(measure.duration).lte(20000);
cy.log(`Ag-grid 1k load took ${measure.duration} milliseconds.`);
cy.get('.ag-root').should('have.attr', 'aria-rowcount', '1001');
cy.get('.ag-center-cols-container')
.find('[role="row"]')
.its('length')
.then((length) => expect(length).to.be.closeTo(20, 3));
cy.get('.ag-cell-label-container').eq(4).click();
cy.get('body').then(($body) => {
for (let i = 0; i < 15; i++) {
cy.wrap($body).realPress('Tab', { pressDelay: 100 });
}
});
cy.focused().parent('.ag-row').should('have.attr', 'row-index', '14');
cy.get('.ag-center-cols-container')
.find('[role="row"]')
.its('length')
.then((length) => expect(length).to.be.closeTo(26, 2));
});
});
});
});
@@ -1,84 +0,0 @@
const marketId = 'market-0';
const marketName = 'ACTIVE MARKET';
describe('market selector', { tags: '@smoke' }, () => {
beforeEach(() => {
cy.mockConsole();
cy.visit(`/trading/${marketId}`);
cy.connectVegaWallet();
cy.wait('@Markets');
});
it('should be properly rendered', () => {
cy.get('input[placeholder="Search"]').should('have.value', marketName);
cy.getByTestId('arrow-button').click();
cy.getByTestId('market-pane').should('be.visible');
cy.getByTestId('market-pane')
.children()
.find('[role="button"]')
.first()
.should('contain.text', marketName);
cy.getByTestId('market-pane')
.children()
.find('[role="button"]')
.first()
.click();
cy.getByTestId('market-pane').should('not.be.visible');
});
it('typing should change list', () => {
cy.get('input[placeholder="Search"]').type('{backspace}');
cy.getByTestId('market-pane')
.children()
.find('[role="button"]')
.should('have.length.at.least', 1);
cy.get('input[placeholder="Search"]').clear();
cy.get('input[placeholder="Search"]').type('ACTIVE');
cy.getByTestId('market-pane')
.children()
.find('[role="button"]')
.should('have.length', 1);
cy.getByTestId('market-pane')
.children()
.find('[role="button"]')
.last()
.click();
cy.location('pathname').should('eq', `/trading/${marketId}`);
cy.get('input[placeholder="Search"]').should('have.value', marketName);
});
// constantly failing on ci
it.skip('keyboard navigation should work well', () => {
cy.get('input[placeholder="Search"]').type('{backspace}');
cy.get('input[placeholder="Search"]').clear();
cy.focused().realPress('ArrowDown');
cy.focused().should('contain.text', marketName);
cy.focused().realPress('ArrowDown');
cy.focused().should('contain.text', 'ETHBTC').realPress('Enter');
cy.location('pathname').should('eq', '/trading/ethbtc-quaterly');
cy.get('input[placeholder="Search"]').type('{backspace}');
cy.get('input[placeholder="Search"]').clear();
cy.getByTestId('market-pane').should('be.visible');
cy.get('body').realPress('ArrowDown');
cy.get('body').realPress('Tab');
cy.getByTestId('market-pane').should('not.be.visible');
});
it('mobile view', () => {
cy.viewport('iphone-xr');
cy.visit(`/trading/${marketId}`);
cy.get('[role="dialog"]').should('not.exist');
cy.getByTestId('arrow-button').click();
cy.get('[role="dialog"]').should('be.visible');
cy.get('input[placeholder="Search"]').then((search) => {
cy.wrap(search).clear();
});
cy.getByTestId('market-pane')
.children()
.find('[role="button"]')
.should('have.length', 3);
cy.get('div[role="dialog"]').should('have.class', 'w-screen');
cy.getByTestId('dialog-close').click();
cy.get('input[placeholder="Search"]').should('have.value', marketName);
});
});
@@ -1,278 +0,0 @@
import { aliasGQLQuery } from '@vegaprotocol/cypress';
import { marketQuery, marketsQuery } from '@vegaprotocol/mock';
const marketId =
marketsQuery().marketsConnection?.edges[1].node.id || 'market-1';
const marketOverride = {
market: {
depth: {
lastTrade: {
price: '9893006',
},
},
id: marketId,
tradableInstrument: {
instrument: {
product: {
settlementAsset: {
id: 'asset-id-2',
name: 'DAI Name',
symbol: 'tDAI',
},
},
},
},
},
};
describe('Market trade with wallet disconnected', { tags: '@smoke' }, () => {
before(() => {
cy.mockConsole();
cy.visit(`/trading/${marketId}`);
cy.wait('@Market');
console.log('marketId', marketId);
});
it('should not display steps', () => {
cy.getByTestId('trading-connect-wallet')
.find('h3')
.should('have.text', 'Please connect your Vega wallet to make a trade');
cy.getByTestId('trading-connect-wallet')
.find('button')
.should('have.text', 'Connect Vega wallet');
cy.getByTestId('trading-connect-wallet')
.find('a')
.should('have.text', 'https://vega.xyz/wallet');
});
});
describe('Market trade', { tags: '@regression' }, () => {
beforeEach(() => {
cy.mockConsole();
cy.mockGQL((req) => {
aliasGQLQuery(req, 'Market', marketQuery(marketOverride));
});
cy.visit(`/trading/${marketId}`);
cy.connectVegaWallet();
cy.wait('@Market');
});
it('side selector should work well', () => {
cy.get('#step-1-control [aria-label^="Selected value"]').should(
'have.text',
'Long'
);
cy.get('#step-1-control [aria-label^="Selected value"]').click();
cy.get('button[aria-label="Open short position"]').click();
cy.get('#step-2-control').click();
cy.get('#step-1-control [aria-label^="Selected value"]').should(
'have.text',
'Short'
);
});
it('side selector mobile view should work well', () => {
cy.viewport('iphone-xr');
cy.getByTestId('next-button').scrollIntoView().click();
cy.get('button[aria-label="Open long position"]').should(
'have.class',
'selected'
);
cy.get('button[aria-label="Open short position"]').should(
'not.have.class',
'selected'
);
cy.get('button[aria-label="Open short position"]').click();
cy.get('button[aria-label="Open long position"]').should(
'not.have.class',
'selected'
);
cy.get('button[aria-label="Open short position"]').should(
'have.class',
'selected'
);
cy.getByTestId('next-button').scrollIntoView().click();
cy.get('#step-1-control').should(
'contain.html',
'aria-label="Selected value Short"'
);
});
it('size slider should work well', () => {
cy.get('#step-1-control [aria-label^="Selected value"]').click();
cy.get('button[aria-label="Open short position"]').click();
cy.get('#step-2-control').click();
cy.get('#step-2-panel')
.find('dd')
.eq(0)
.find('button')
.should('have.text', '1');
cy.get('#step-2-panel').find('[role="slider"]').type('{rightarrow}');
cy.get('#step-2-panel')
.find('dd')
.eq(0)
.find('button')
.should('have.text', '2');
});
it('percentage selection should work well', () => {
cy.get('#step-1-control [aria-label^="Selected value"]').click();
cy.get('button[aria-label="Open short position"]').click();
cy.get('#step-2-control').click();
cy.get('#step-2-panel')
.find('dd')
.eq(0)
.find('button')
.should('have.text', '1');
cy.getByTestId('max-label').should('have.text', '10');
cy.getByTestId('percentage-selector')
.find('button')
.contains('Max')
.click();
cy.get('#step-2-panel')
.find('dd')
.eq(0)
.find('button')
.should('have.text', '10');
});
it('size input should work well', () => {
cy.get('#step-1-control [aria-label^="Selected value"]').click();
cy.get('button[aria-label="Open short position"]').click();
cy.get('#step-2-control').click();
cy.get('#step-2-panel')
.find('dd')
.eq(0)
.find('button')
.should('have.text', '1');
cy.get('#step-2-panel').find('dd').eq(0).find('button').click();
cy.get('#step-2-panel').find('dd').eq(0).find('input').type('{backspace}2');
cy.get('#step-2-panel').find('dd').eq(0).find('button').click();
cy.get('#step-2-panel')
.find('dd')
.eq(0)
.find('button')
.should('have.text', '2');
cy.get('button').contains('Max').click();
});
it('slippage value should be displayed', () => {
cy.get('#step-1-control [aria-label^="Selected value"]').click();
cy.get('button[aria-label="Open short position"]').click();
cy.get('#step-2-control').click();
cy.get('button').contains('Max').click();
cy.get('#step-2-panel')
.find('dl')
.eq(2)
.find('dd')
.should('have.text', '0.01%');
});
it('allow slippage value to be adjusted', () => {
cy.get('#step-1-control [aria-label^="Selected value"]').click();
cy.get('button[aria-label="Open short position"]').click();
cy.get('#step-2-control').click();
cy.get('button').contains('Max').click();
cy.get('#step-2-panel')
.find('dl')
.eq(2)
.find('dd')
.should('have.text', '0.01%');
cy.get('#step-2-panel').find('dl').eq(2).find('button').click();
cy.get('#input-order-slippage')
.focus()
.type('{backspace}{backspace}{backspace}1');
cy.getByTestId('slippage-dialog').find('button').click();
cy.get('#step-2-panel')
.find('dl')
.eq(2)
.find('dd')
.should('have.text', '1%');
});
it('notional position size should be present', () => {
cy.get('#step-1-control [aria-label^="Selected value"]').click();
cy.get('button[aria-label="Open short position"]').click();
cy.get('#step-2-control').click();
cy.get('#step-2-panel')
.find('dd')
.eq(0)
.find('button')
.should('have.text', '1');
cy.get('#step-2-panel').find('dd').eq(0).find('button').click();
cy.get('#step-2-panel').find('dd').eq(0).find('input').type('{backspace}2');
cy.get('#step-2-panel').find('dd').eq(0).find('button').click();
cy.get('#step-2-panel')
.find('dt')
.eq(2)
.should('have.text', 'Est. Position Size (tDAI)');
cy.get('#step-2-panel').find('dd').eq(2).should('have.text', '197.86012');
});
it('total fees should be displayed', () => {
cy.get('#step-1-control [aria-label^="Selected value"]').click();
cy.get('button[aria-label="Open short position"]').click();
cy.get('#step-2-control').click();
cy.get('#step-2-panel')
.find('dt')
.eq(3)
.should('have.text', 'Est. Fees (tDAI)');
cy.get('#step-2-panel')
.find('dd')
.eq(3)
.should('have.text', '3.00 (3.03%)');
});
it('order review should display proper calculations', () => {
cy.get('#step-3-control').click();
cy.getByTestId('review-trade')
.get('#contracts_tooltip_trigger')
.trigger('click')
.realTouch();
cy.get('[data-radix-popper-content-wrapper]').contains(
'The number of contracts determines'
);
cy.get('#step-3-panel').find('dd').eq(1).should('have.text', '1');
cy.get('#step-3-panel').find('dd').eq(2).should('have.text', '98.93006');
cy.get('#step-3-panel')
.find('dd')
.eq(3)
.should('have.text', '3.00 (3.03%)');
cy.get('#step-3-panel')
.find('dd')
.eq(4)
.should('have.text', '45,126.90058');
cy.getByTestId('place-order').should('be.enabled').click();
});
it('info tooltip on mobile view should work well', () => {
cy.viewport('iphone-xr');
cy.get('#step-3-control').click();
// Start from the bottom tooltip to ensure the tooltip above
// can be interacted with
cy.getByTestId('review-trade').get('div.cursor-help').eq(1).realTouch();
cy.get('[data-radix-popper-content-wrapper]').contains(
'The notional size represents the position size'
);
cy.getByTestId('review-trade')
.get('#contracts_tooltip_trigger')
.realTouch();
cy.get('[data-radix-popper-content-wrapper]').contains(
'The number of contracts determines'
);
});
});
@@ -1,194 +0,0 @@
import { aliasGQLQuery } from '@vegaprotocol/cypress';
import {
accountsQuery,
assetsQuery,
chainIdQuery,
fillsQuery,
marginsQuery,
marketsDataQuery,
marketsQuery,
ordersQuery,
positionsQuery,
statisticsQuery,
} from '@vegaprotocol/mock';
describe('Portfolio page - wallet', { tags: '@smoke' }, () => {
it('button for wallet connect should work', () => {
cy.visit('/');
cy.get('[href="/portfolio"]').eq(0).click();
cy.getByTestId('trading-connect-wallet').should('be.visible');
cy.connectVegaWallet();
cy.getByTestId('trading-connect-wallet').should('not.exist');
});
});
describe('Portfolio page tabs', { tags: '@smoke' }, () => {
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());
});
});
it('certain tabs should exist', () => {
cy.visit('/portfolio');
cy.connectVegaWallet();
cy.getByTestId('assets').click();
cy.location('pathname').should('eq', '/portfolio/assets');
cy.getByTestId('positions').click();
cy.location('pathname').should('eq', '/portfolio/positions');
cy.getByTestId('orders').click();
cy.location('pathname').should('eq', '/portfolio/orders');
cy.getByTestId('fills').click();
cy.location('pathname').should('eq', '/portfolio/fills');
cy.getByTestId('deposits').click();
cy.location('pathname').should('eq', '/portfolio/deposits');
});
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());
});
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.getByTestId('dialog-title').should(
'have.text',
'Asset details - tEURO'
);
cy.getByTestId('dialog-close').click();
});
});
describe('Positions view', () => {
beforeEach(() => {
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());
});
cy.visit('/portfolio/positions');
cy.connectVegaWallet();
});
it('data should be properly rendered', () => {
cy.get('.ag-center-cols-container .ag-row').should('have.length', 2);
});
});
describe('Orders view', () => {
beforeEach(() => {
cy.mockGQL((req) => {
aliasGQLQuery(req, 'ChainId', chainIdQuery());
aliasGQLQuery(req, 'Statistics', statisticsQuery());
aliasGQLQuery(req, 'Orders', ordersQuery());
aliasGQLQuery(req, 'Markets', marketsQuery());
});
cy.visit('/portfolio/orders');
cy.connectVegaWallet();
});
it('data should be properly rendered', () => {
cy.get('.ag-center-cols-container .ag-row').should('have.length', 5);
});
});
describe('Fills view', () => {
beforeEach(() => {
cy.mockGQL((req) => {
aliasGQLQuery(req, 'ChainId', chainIdQuery());
aliasGQLQuery(req, 'Statistics', statisticsQuery());
aliasGQLQuery(req, 'Orders', ordersQuery());
aliasGQLQuery(req, 'Markets', marketsQuery());
aliasGQLQuery(req, 'Fills', fillsQuery());
});
cy.visit('/portfolio/fills');
cy.connectVegaWallet();
});
it('data should be properly rendered', () => {
cy.get('.ag-center-cols-container .ag-row').should('have.length', 4);
});
});
describe('Empty views', () => {
beforeEach(() => {
cy.mockGQL((req) => {
aliasGQLQuery(req, 'ChainId', chainIdQuery());
aliasGQLQuery(req, 'Statistics', statisticsQuery());
aliasGQLQuery(req, 'Positions', { party: null });
aliasGQLQuery(req, 'Accounts', { party: null });
aliasGQLQuery(req, 'Orders', { party: null });
aliasGQLQuery(req, 'Fills', { party: null });
aliasGQLQuery(req, 'Markets', {
marketsConnection: { edges: [], __typename: 'MarketConnection' },
});
aliasGQLQuery(req, 'Assets', {
assetsConnection: { edges: null, __typename: 'AssetsConnection' },
});
aliasGQLQuery(req, 'Margins', marginsQuery());
aliasGQLQuery(req, 'MarketsData', marketsDataQuery());
});
cy.visit('/portfolio');
cy.connectVegaWallet();
});
it('"No data to display" should be always displayed', () => {
cy.getByTestId('assets').click();
cy.get('div.flex.items-center.justify-center').should(
'contain.text',
'No data to display'
);
cy.getByTestId('positions').click();
cy.get('div.flex.items-center.justify-center').should(
'contain.text',
'No data to display'
);
cy.getByTestId('orders').click();
cy.get('div.flex.items-center.justify-center').should(
'contain.text',
'No data to display'
);
cy.getByTestId('fills').click();
cy.get('div.flex.items-center.justify-center').should(
'contain.text',
'No data to display'
);
});
});
});
@@ -1,56 +0,0 @@
import { aliasGQLQuery } from '@vegaprotocol/cypress';
import type { CyHttpMessages } from 'cypress/types/net-stubbing';
import {
accountsQuery,
assetsQuery,
chainIdQuery,
estimateOrderQuery,
fillsQuery,
marginsQuery,
marketDataQuery,
marketDepthQuery,
marketQuery,
marketsCandlesQuery,
marketsDataQuery,
marketsQuery,
ordersQuery,
positionsQuery,
statisticsQuery,
} from '@vegaprotocol/mock';
declare global {
// eslint-disable-next-line @typescript-eslint/no-namespace
namespace Cypress {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
interface Chainable<Subject> {
mockConsole(): void;
}
}
}
const mockPage = (req: CyHttpMessages.IncomingHttpRequest) => {
aliasGQLQuery(req, 'ChainId', chainIdQuery());
aliasGQLQuery(req, 'Statistics', statisticsQuery());
aliasGQLQuery(req, 'Markets', marketsQuery());
aliasGQLQuery(req, 'MarketsCandles', marketsCandlesQuery());
aliasGQLQuery(req, 'MarketsData', marketsDataQuery());
aliasGQLQuery(req, 'MarketData', marketDataQuery());
aliasGQLQuery(req, 'Market', marketQuery());
aliasGQLQuery(req, 'MarketTags', {});
aliasGQLQuery(req, 'EstimateOrder', estimateOrderQuery());
aliasGQLQuery(req, 'MarketNames', {});
aliasGQLQuery(req, 'MarketDepth', marketDepthQuery());
aliasGQLQuery(req, 'Positions', positionsQuery());
aliasGQLQuery(req, 'Margins', marginsQuery());
aliasGQLQuery(req, 'Accounts', accountsQuery());
aliasGQLQuery(req, 'Assets', assetsQuery());
aliasGQLQuery(req, 'SimpleMarkets', marketsQuery());
aliasGQLQuery(req, 'Orders', ordersQuery());
aliasGQLQuery(req, 'Fills', fillsQuery());
};
export const addMockConsole = () => {
Cypress.Commands.add('mockConsole', () => {
cy.mockGQL(mockPage);
});
};
@@ -1,7 +0,0 @@
import '@vegaprotocol/cypress';
import 'cypress-real-events/support';
import registerCypressGrep from '@cypress/grep';
import { addMockConsole } from './console-mock';
registerCypressGrep();
addMockConsole();
-13
View File
@@ -1,13 +0,0 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"strict": true,
"jsx": "react-jsx",
"sourceMap": false,
"allowSyntheticDefaultImports": true,
"outDir": "../../dist/out-tsc",
"allowJs": true,
"types": ["cypress", "node", "cypress-real-events", "@cypress/grep"]
},
"include": ["src/**/*.ts", "src/**/*.js", "./declaration.d.ts", "index.d.ts"]
}
-11
View File
@@ -1,11 +0,0 @@
{
"presets": [
[
"@nrwl/react/babel",
{
"runtime": "automatic"
}
]
],
"plugins": []
}
-16
View File
@@ -1,16 +0,0 @@
# This file is used by:
# 1. autoprefixer to adjust CSS to support the below specified browsers
# 2. babel preset-env to adjust included polyfills
#
# For additional information regarding the format and rule options, please see:
# https://github.com/browserslist/browserslist#queries
#
# If you need to support different browsers in production, you may tweak the list below.
last 1 Chrome version
last 1 Firefox version
last 2 Edge major versions
last 2 Safari major version
last 2 iOS major versions
Firefox ESR
not IE 9-11 # For IE 9-11 support, remove 'not'.
-27
View File
@@ -1,27 +0,0 @@
# React Environment Variables
# https://facebook.github.io/create-react-app/docs/adding-custom-environment-variables#expanding-environment-variables-in-env
# Netlify Environment Variables
# https://www.netlify.com/docs/continuous-deployment/#environment-variables
NX_VERSION=$npm_package_version
NX_REPOSITORY_URL=$REPOSITORY_URL
NX_BRANCH=$BRANCH
NX_PULL_REQUEST=$PULL_REQUEST
NX_HEAD=$HEAD
NX_COMMIT_REF=$COMMIT_REF
NX_CONTEXT=$CONTEXT
NX_REVIEW_ID=$REVIEW_ID
NX_INCOMING_HOOK_TITLE=$INCOMING_HOOK_TITLE
NX_INCOMING_HOOK_URL=$INCOMING_HOOK_URL
NX_INCOMING_HOOK_BODY=$INCOMING_HOOK_BODY
NX_URL=$URL
NX_DEPLOY_URL=$DEPLOY_URL
NX_DEPLOY_PRIME_URL=$DEPLOY_PRIME_URL
NX_VEGA_CONFIG_URL="https://static.vega.xyz/assets/stagnet3-network.json"
NX_VEGA_ENV=STAGNET3
NX_VEGA_URL="https://api.stagnet3.vega.xyz/graphql"
NX_VEGA_WALLET_URL=http://localhost:1789
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_VEGA_NETWORKS={"MAINNET":"https://alpha.console.vega.xyz"}
NX_VEGA_EXPLORER_URL=https://explorer.fairground.wtf
-3
View File
@@ -1,3 +0,0 @@
# App configuration variables
NX_VEGA_URL=http://localhost:3028/query
NX_VEGA_ENV=LOCAL
-8
View File
@@ -1,8 +0,0 @@
# App configuration variables
NX_VEGA_CONFIG_URL=https://static.vega.xyz/assets/devnet-network.json
NX_VEGA_URL=https://api.n04.d.vega.xyz/graphql
NX_VEGA_ENV=DEVNET
NX_VEGA_NETWORKS={\"MAINNET\":\"https://alpha.console.vega.xyz\"}
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_VEGA_EXPLORER_URL=https://dev.explorer.vega.xyz
-8
View File
@@ -1,8 +0,0 @@
# App configuration variables
NX_VEGA_CONFIG_URL=https://static.vega.xyz/assets/mainnet-network.json
NX_VEGA_URL=https://api.vega.xyz/query
NX_VEGA_ENV=MAINNET
NX_VEGA_NETWORKS='{\"MAINNET\":\"https://alpha.console.vega.xyz\"}'
NX_ETHEREUM_PROVIDER_URL=https://mainnet.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
NX_ETHERSCAN_URL=https://etherscan.io
NX_VEGA_EXPLORER_URL=https://explorer.vega.xyz
-7
View File
@@ -1,7 +0,0 @@
NX_VEGA_CONFIG_URL=https://static.vega.xyz/assets/sandbox-network.json
NX_VEGA_URL=https://api.sandbox.vega.xyz/graphql
NX_VEGA_ENV=SANDBOX
NX_VEGA_NETWORKS='{"DEVNET":"https://dev.token.vega.xyz","STAGNET3":"https://stagnet3.token.vega.xyz","STAGNET1":"https://stagnet1.token.vega.xyz","TESTNET":"https://token.fairground.wtf","MAINNET":"https://token.vega.xyz"}'
NX_VEGA_CONFIG_URL=https://static.vega.xyz/assets/sandbox-network.json
NX_VEGA_EXPLORER_URL=https://sandbox.explorer.vega.xyz
NX_VEGA_DOCS_URL=https://docs.vega.xyz/testnet
-7
View File
@@ -1,7 +0,0 @@
# App configuration variables
NX_VEGA_CONFIG_URL=https://static.vega.xyz/assets/stagnet3-network.json
NX_VEGA_URL=https://api.stagnet3.vega.xyz/graphql
NX_VEGA_ENV=STAGNET3
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_VEGA_EXPLORER_URL=https://stagnet3.explorer.vega.xyz
-8
View File
@@ -1,8 +0,0 @@
# App configuration variables
NX_VEGA_CONFIG_URL=https://static.vega.xyz/assets/testnet-network.json
NX_VEGA_URL=https://api.n12.testnet.vega.xyz/graphql
NX_VEGA_ENV=TESTNET
NX_VEGA_NETWORKS='{\"MAINNET\":\"https://alpha.console.vega.xyz\"}'
NX_ETHEREUM_PROVIDER_URL=https://sepolia.infura.io/v3/4f846e79e13f44d1b51bbd7ed9edefb8
NX_ETHERSCAN_URL=https://sepolia.etherscan.io
NX_VEGA_EXPLORER_URL=https://explorer.fairground.wtf
-18
View File
@@ -1,18 +0,0 @@
{
"extends": ["plugin:@nrwl/nx/react", "../../.eslintrc.json"],
"ignorePatterns": ["!**/*", "__generated__", "__generated___"],
"overrides": [
{
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
"rules": {}
},
{
"files": ["*.ts", "*.tsx"],
"rules": {}
},
{
"files": ["*.js", "*.jsx"],
"rules": {}
}
]
}
-12
View File
@@ -1,12 +0,0 @@
/* eslint-disable */
export default {
displayName: 'console-lite',
preset: '../../jest.preset.js',
transform: {
'^(?!.*\\.(js|jsx|ts|tsx|css|json)$)': '@nrwl/react/plugins/jest',
'^.+\\.[tj]sx?$': ['babel-jest', { presets: ['@nrwl/next/babel'] }],
},
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
coverageDirectory: '../../coverage/apps/console-lite',
setupFilesAfterEnv: ['./setup-tests.ts'],
};
-4
View File
@@ -1,4 +0,0 @@
[[redirects]]
from = "/*"
to = "/index.html"
status = 200
-10
View File
@@ -1,10 +0,0 @@
const { join } = require('path');
module.exports = {
plugins: {
tailwindcss: {
config: join(__dirname, 'tailwind.config.js'),
},
autoprefixer: {},
},
};
-90
View File
@@ -1,90 +0,0 @@
{
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "apps/console-lite/src",
"projectType": "application",
"targets": {
"build": {
"executor": "./tools/executors/webpack:build",
"outputs": ["{options.outputPath}"],
"defaultConfiguration": "production",
"options": {
"compiler": "babel",
"outputPath": "dist/apps/console-lite",
"index": "apps/console-lite/src/index.html",
"baseHref": "/",
"main": "apps/console-lite/src/main.tsx",
"polyfills": "apps/console-lite/src/polyfills.ts",
"tsConfig": "apps/console-lite/tsconfig.app.json",
"assets": [
"apps/console-lite/src/favicon.ico",
"apps/console-lite/src/assets"
],
"styles": ["apps/console-lite/src/styles.scss"],
"scripts": [],
"webpackConfig": "@nrwl/react/plugins/webpack"
},
"configurations": {
"production": {
"fileReplacements": [
{
"replace": "apps/console-lite/src/environments/environment.ts",
"with": "apps/console-lite/src/environments/environment.prod.ts"
}
],
"optimization": true,
"outputHashing": "all",
"sourceMap": false,
"namedChunks": false,
"extractLicenses": true,
"vendorChunk": false
}
}
},
"serve": {
"executor": "./tools/executors/webpack:serve",
"options": {
"buildTarget": "console-lite:build:development",
"hmr": true,
"port": 4001
},
"configurations": {
"production": {
"buildTarget": "console-lite:build:production",
"hmr": false
}
}
},
"lint": {
"executor": "@nrwl/linter:eslint",
"outputs": ["{options.outputFile}"],
"options": {
"lintFilePatterns": ["apps/console-lite/**/*.{ts,tsx,js,jsx}"]
}
},
"test": {
"executor": "@nrwl/jest:jest",
"outputs": ["coverage/apps/console-lite"],
"options": {
"jestConfig": "apps/console-lite/jest.config.ts",
"passWithNoTests": true
}
},
"build-netlify": {
"executor": "@nrwl/workspace:run-commands",
"options": {
"commands": [
"cp apps/console-lite/netlify.toml netlify.toml",
"nx build console-lite"
]
}
},
"build-spec": {
"executor": "@nrwl/workspace:run-commands",
"outputs": [],
"options": {
"command": "yarn tsc --project ./apps/console-lite/tsconfig.spec.json"
}
}
},
"tags": []
}
-77
View File
@@ -1,77 +0,0 @@
import { useEffect } from 'react';
import { useLocation } from 'react-router-dom';
import { EnvironmentProvider, NetworkLoader } from '@vegaprotocol/environment';
import {
VegaConnectDialog,
VegaManageDialog,
VegaWalletProvider,
} from '@vegaprotocol/wallet';
import { Connectors } from './lib/vega-connectors';
import '../styles.scss';
import { AppLoader } from './components/app-loader';
import Header from './components/header';
import { Main } from './components/main';
import LocalContext from './context/local-context';
import useLocalValues from './hooks/use-local-values';
import type { InMemoryCacheConfig } from '@apollo/client';
function App() {
const localValues = useLocalValues();
const {
vegaWalletDialog,
menu: { setMenuOpen },
} = localValues;
const location = useLocation();
useEffect(() => {
setMenuOpen(false);
}, [location, setMenuOpen]);
const cacheConfig: InMemoryCacheConfig = {
typePolicies: {
Market: {
merge: true,
},
Party: {
merge: true,
},
Query: {},
Account: {
keyFields: false,
fields: {
balanceFormatted: {},
},
},
Node: {
keyFields: false,
},
Instrument: {
keyFields: false,
},
},
};
return (
<EnvironmentProvider>
<NetworkLoader cache={cacheConfig}>
<VegaWalletProvider>
<LocalContext.Provider value={localValues}>
<AppLoader>
<div className="max-h-full min-h-full dark:bg-lite-black dark:text-neutral-200 bg-white text-neutral-800 grid grid-rows-[min-content,1fr]">
<Header />
<Main />
<VegaConnectDialog connectors={Connectors} />
<VegaManageDialog
dialogOpen={vegaWalletDialog.manage}
setDialogOpen={vegaWalletDialog.setManage}
/>
</div>
</AppLoader>
</LocalContext.Provider>
</VegaWalletProvider>
</NetworkLoader>
</EnvironmentProvider>
);
}
export default App;
@@ -1,19 +0,0 @@
import { useEagerConnect } from '@vegaprotocol/wallet';
import type { ReactNode } from 'react';
import { Connectors } from '../../lib/vega-connectors';
interface AppLoaderProps {
children: ReactNode;
}
/**
* Component to handle any app initialization, startup querys and other things
* that must happen for it can be used
*/
export function AppLoader({ children }: AppLoaderProps) {
// Get keys from vega wallet immediately
useEagerConnect(Connectors);
// eslint-disable-next-line react/jsx-no-useless-fragment
return <>{children}</>;
}
@@ -1,109 +0,0 @@
import React, { forwardRef, useCallback, useMemo, useRef } from 'react';
import classNames from 'classnames';
import type { AgGridReact } from 'ag-grid-react';
import { AgGridDynamic as AgGrid } from '@vegaprotocol/ui-toolkit';
import {
useScreenDimensions,
useThemeSwitcher,
} from '@vegaprotocol/react-helpers';
import type {
GridOptions,
GetRowIdParams,
TabToNextCellParams,
CellKeyDownEvent,
FullWidthCellKeyDownEvent,
IGetRowsParams,
IDatasource,
} from 'ag-grid-community';
import { NO_DATA_MESSAGE } from '../../constants';
import * as constants from '../simple-market-list/constants';
export interface GetRowsParams<T>
extends Omit<IGetRowsParams, 'successCallback'> {
successCallback(rowsThisBlock: T[], lastRow?: number): void;
}
export interface Datasource<T> extends IDatasource {
getRows(params: GetRowsParams<T>): void;
}
interface Props<T> extends GridOptions {
rowData?: T[];
datasource?: Datasource<T>;
handleRowClicked?: (event: { data: T }) => void;
components?: Record<string, unknown>;
classNamesParam?: string | string[];
}
const ConsoleLiteGrid = <T extends { id?: string }>(
{ handleRowClicked, getRowId, classNamesParam, ...props }: Props<T>,
ref?: React.Ref<AgGridReact>
) => {
const { isMobile, screenSize } = useScreenDimensions();
const gridRef = useRef<AgGridReact | null>(null);
const { theme } = useThemeSwitcher();
const handleOnGridReady = useCallback(() => {
(
(ref as React.RefObject<AgGridReact>) || gridRef
).current?.api?.sizeColumnsToFit();
}, [gridRef, ref]);
const onTabToNextCell = useCallback((params: TabToNextCellParams) => {
const {
api,
previousCellPosition: { rowIndex },
} = params;
const rowCount = api.getDisplayedRowCount();
if (rowCount <= rowIndex + 1) {
return null;
}
return { ...params.previousCellPosition, rowIndex: rowIndex + 1 };
}, []);
const getRowIdLocal = useCallback(({ data }: GetRowIdParams) => data.id, []);
const onCellKeyDown = useCallback(
(
params: (CellKeyDownEvent | FullWidthCellKeyDownEvent) & {
event: KeyboardEvent;
}
) => {
const { event: { key = '' } = {}, data } = params;
if (key === 'Enter') {
handleRowClicked?.({ data });
}
},
[handleRowClicked]
);
const shouldSuppressHorizontalScroll = useMemo(() => {
return !isMobile && constants.LARGE_SCREENS.includes(screenSize);
}, [isMobile, screenSize]);
return (
<AgGrid
className={classNames(classNamesParam)}
rowHeight={60}
customThemeParams={
theme === 'dark'
? constants.agGridDarkVariables
: constants.agGridLightVariables
}
onGridReady={handleOnGridReady}
onRowClicked={handleRowClicked}
rowClass={isMobile ? 'mobile' : ''}
rowClassRules={constants.ROW_CLASS_RULES}
ref={ref || gridRef}
overlayNoRowsTemplate={NO_DATA_MESSAGE}
suppressContextMenu
getRowId={getRowId || getRowIdLocal}
suppressMovableColumns
suppressRowTransform
onCellKeyDown={onCellKeyDown}
tabToNextCell={onTabToNextCell}
suppressHorizontalScroll={shouldSuppressHorizontalScroll}
{...props}
/>
);
};
const ConsoleLiteGridForwarder = forwardRef(ConsoleLiteGrid) as <T>(
p: Props<T> & { ref?: React.Ref<AgGridReact> }
) => React.ReactElement;
export default ConsoleLiteGridForwarder;
@@ -1 +0,0 @@
export { default as ConsoleLiteGrid } from './console-lite-grid';
@@ -1,11 +0,0 @@
query MarketTags($marketId: ID!) {
market(id: $marketId) {
tradableInstrument {
instrument {
metadata {
tags
}
}
}
}
}
@@ -1,54 +0,0 @@
import * as Types from '@vegaprotocol/types';
import { gql } from '@apollo/client';
import * as Apollo from '@apollo/client';
const defaultOptions = {} as const;
export type MarketTagsQueryVariables = Types.Exact<{
marketId: Types.Scalars['ID'];
}>;
export type MarketTagsQuery = { __typename?: 'Query', market?: { __typename?: 'Market', tradableInstrument: { __typename?: 'TradableInstrument', instrument: { __typename?: 'Instrument', metadata: { __typename?: 'InstrumentMetadata', tags?: Array<string> | null } } } } | null };
export const MarketTagsDocument = gql`
query MarketTags($marketId: ID!) {
market(id: $marketId) {
tradableInstrument {
instrument {
metadata {
tags
}
}
}
}
}
`;
/**
* __useMarketTagsQuery__
*
* To run a query within a React component, call `useMarketTagsQuery` and pass it any options that fit your needs.
* When your component renders, `useMarketTagsQuery` returns an object from Apollo Client that contains loading, error, and data properties
* you can use to render your UI.
*
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
*
* @example
* const { data, loading, error } = useMarketTagsQuery({
* variables: {
* marketId: // value for 'marketId'
* },
* });
*/
export function useMarketTagsQuery(baseOptions: Apollo.QueryHookOptions<MarketTagsQuery, MarketTagsQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useQuery<MarketTagsQuery, MarketTagsQueryVariables>(MarketTagsDocument, options);
}
export function useMarketTagsLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<MarketTagsQuery, MarketTagsQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useLazyQuery<MarketTagsQuery, MarketTagsQueryVariables>(MarketTagsDocument, options);
}
export type MarketTagsQueryHookResult = ReturnType<typeof useMarketTagsQuery>;
export type MarketTagsLazyQueryHookResult = ReturnType<typeof useMarketTagsLazyQuery>;
export type MarketTagsQueryResult = Apollo.QueryResult<MarketTagsQuery, MarketTagsQueryVariables>;
@@ -1,36 +0,0 @@
import React from 'react';
import Video from '../header/video';
import Comet from '../header/comet';
import Star from '../icons/star';
const Baubles = () => {
return (
<aside className="relative right-0 top-0 h-[700px] hidden md:block md:w-1/2 overflow-hidden">
<div className="absolute top-[100px] w-[393px] left-[19%] h-[517px]">
<div className="absolute top-[82px] right-[34px] w-[100px] h-[100px] clip-path-rounded">
<Video />
</div>
<div className="absolute bottom-[100px] left-[59px] w-[200px] h-[200px] clip-path-rounded">
<Video />
</div>
<div className="absolute w-[118px] h-[85px] right-0 bottom-[178px]">
<Comet />
</div>
<div className="absolute w-[118px] h-[82px] left-0 bottom-[120px]">
<Comet />
</div>
<div className="absolute w-[20px] h-[20px] top-0 left-[49px]">
<Star />
</div>
<div className="absolute w-[20px] h-[20px] top-[89px] left-[184px]">
<Star />
</div>
<div className="absolute w-[10px] h-[10px] bottom-0 right-[137px]">
<Star />
</div>
</div>
</aside>
);
};
export default Baubles;
@@ -1,61 +0,0 @@
import React from 'react';
import { render } from '@testing-library/react';
import { MockedProvider } from '@apollo/client/testing';
import type { MarketDealTicketAsset } from '@vegaprotocol/market-list';
import { DealTicketBalance } from './deal-ticket-balance';
jest.mock('@vegaprotocol/wallet', () => ({
...jest.requireActual('@vegaprotocol/wallet'),
useVegaWallet: jest.fn().mockReturnValue('wallet-pub-key'),
}));
const tDAI: MarketDealTicketAsset = {
__typename: 'Asset',
id: '1',
symbol: 'tDAI',
name: 'TDAI',
decimals: 2,
};
let mockAccountBalance: {
accountBalance: string;
accountDecimals: number | null;
} = { accountBalance: '1000000', accountDecimals: 2 };
jest.mock('@vegaprotocol/accounts', () => ({
...jest.requireActual('@vegaprotocol/accounts'),
useAccountBalance: jest.fn(() => mockAccountBalance),
}));
describe('DealTicketBalance', function () {
it('should render the balance', () => {
const { getByText, getByRole } = render(
<DealTicketBalance settlementAsset={tDAI} isWalletConnected />,
{ wrapper: MockedProvider }
);
expect(getByRole('complementary')).toHaveAccessibleName('tDAI Balance');
expect(getByText('10,000.00')).toBeInTheDocument();
expect(getByText('tDAI')).toBeInTheDocument();
});
it('should prompt to connect wallet', () => {
const { getByText } = render(
<DealTicketBalance settlementAsset={tDAI} isWalletConnected={false} />,
{ wrapper: MockedProvider }
);
expect(
getByText('Please connect your Vega wallet to see your balance')
).toBeInTheDocument();
});
it('should display zero balance', () => {
mockAccountBalance = { accountBalance: '', accountDecimals: null };
const { getByText } = render(
<DealTicketBalance settlementAsset={tDAI} isWalletConnected={true} />,
{ wrapper: MockedProvider }
);
expect(getByText('No tDAI left to trade')).toBeInTheDocument();
});
});
@@ -1,58 +0,0 @@
import classNames from 'classnames';
import {
addDecimalsFormatNumber,
t,
toBigNum,
} from '@vegaprotocol/react-helpers';
import type { MarketDealTicket } from '@vegaprotocol/market-list';
import { useAccountBalance } from '@vegaprotocol/accounts';
interface DealTicketBalanceProps {
settlementAsset: MarketDealTicket['tradableInstrument']['instrument']['product']['settlementAsset'];
isWalletConnected: boolean;
className?: string;
}
export const DealTicketBalance = ({
settlementAsset,
isWalletConnected,
className = '',
}: DealTicketBalanceProps) => {
const settlementAssetId = settlementAsset?.id;
const settlementAssetSymbol = settlementAsset?.symbol;
const { accountBalance, accountDecimals } =
useAccountBalance(settlementAssetId) || {};
const settlementBalance = toBigNum(accountBalance || 0, accountDecimals || 0);
const formattedNumber =
accountBalance &&
accountDecimals &&
addDecimalsFormatNumber(accountBalance, accountDecimals);
const balance = (
<p className="text-blue text-lg font-semibold">
{!settlementBalance.isZero()
? t(`${formattedNumber}`)
: `No ${settlementAssetSymbol} left to trade`}
</p>
);
const connectWallet = (
<p>{t('Please connect your Vega wallet to see your balance')}</p>
);
const ariaLabel = t(`${settlementAssetSymbol} Balance`);
return (
<aside
aria-label={ariaLabel}
className={classNames('text-right', className)}
>
<div className="inline-block">
<span className="text-blue">{settlementAssetSymbol}</span>
{isWalletConnected ? balance : connectWallet}
</div>
</aside>
);
};
@@ -1,75 +0,0 @@
import { useParams } from 'react-router-dom';
import { DealTicketManager } from '@vegaprotocol/deal-ticket';
import { Loader, Splash } from '@vegaprotocol/ui-toolkit';
import { t, useDataProvider } from '@vegaprotocol/react-helpers';
import { useVegaWallet } from '@vegaprotocol/wallet';
import { DealTicketSteps } from './deal-ticket-steps';
import { DealTicketBalance } from './deal-ticket-balance';
import Baubles from './baubles-decor';
import ConnectWallet from '../wallet-connector';
import { useMemo } from 'react';
import type {
MarketDataUpdateFieldsFragment,
MarketDealTicket,
} from '@vegaprotocol/market-list';
import { marketDealTicketProvider } from '@vegaprotocol/market-list';
const tempEmptyText = (
<p>{t('Please select a market from the markets page')}</p>
);
export const DealTicketContainer = () => {
const { marketId } = useParams<{ marketId: string }>();
const { pubKey } = useVegaWallet();
const variables = useMemo(
() => ({
marketId: marketId || '',
}),
[marketId]
);
const { data, loading } = useDataProvider<
MarketDealTicket,
MarketDataUpdateFieldsFragment
>({
dataProvider: marketDealTicketProvider,
variables,
skip: !marketId,
});
const loader = <Loader />;
if (marketId && data) {
const balance = (
<DealTicketBalance
className="mb-4"
settlementAsset={
data.tradableInstrument.instrument.product?.settlementAsset
}
isWalletConnected={!!pubKey}
/>
);
const container = (
<DealTicketManager market={data}>
{loading ? loader : balance}
<DealTicketSteps market={data} />
</DealTicketManager>
);
return (
<section className="flex p-4 md:p-6">
<section className="w-full md:w-1/2 md:min-w-[500px]">
{pubKey ? container : <ConnectWallet />}
</section>
<Baubles />
</section>
);
}
return marketId ? (
<Splash>
<p>{t('Could not load market')}</p>
</Splash>
) : (
tempEmptyText
);
};
@@ -1,149 +0,0 @@
import React, { useCallback, useState } from 'react';
import { BigNumber } from 'bignumber.js';
import { t } from '@vegaprotocol/react-helpers';
import {
SliderRoot,
SliderThumb,
SliderTrack,
SliderRange,
FormGroup,
} from '@vegaprotocol/ui-toolkit';
import { InputSetter } from '../input-setter';
interface DealTicketSizeInputProps {
step: number;
min: number;
max: number;
value: number;
onValueChange: (value: number) => void;
positionDecimalPlaces: number;
}
const getSizeLabel = (value: number): string => {
const MIN_LABEL = 'Min';
const MAX_LABEL = 'Max';
if (value === 0) {
return MIN_LABEL;
} else if (value === 100) {
return MAX_LABEL;
}
return `${value}%`;
};
export const DealTicketSizeInput = ({
value,
step,
min,
max,
onValueChange,
positionDecimalPlaces,
}: DealTicketSizeInputProps) => {
const sizeRatios = [0, 25, 50, 75, 100];
const [inputValue, setInputValue] = useState(value);
const onInputValueChange = useCallback(
(event: React.ChangeEvent<HTMLInputElement>) => {
let value = parseFloat(event.target.value);
const isLessThanMin = value < min;
const isMoreThanMax = value > max;
if (isLessThanMin) {
value = min;
} else if (isMoreThanMax) {
value = max;
}
if (value) {
onValueChange(value);
}
setInputValue(value);
},
[min, max, onValueChange, setInputValue]
);
const onButtonValueChange = (size: number) => {
const newVal = new BigNumber(size)
.decimalPlaces(positionDecimalPlaces)
.toNumber();
onValueChange(newVal);
setInputValue(newVal);
};
const onSliderValueChange = useCallback(
(value: number[]) => {
const val = value[0];
setInputValue(val);
onValueChange(val);
},
[onValueChange]
);
return (
<div>
<div className="flex justify-between text-black dark:text-white mb-2">
<span data-testid="min-label">{min}</span>
<span data-testid="max-label">{max}</span>
</div>
<SliderRoot
className="mb-2"
value={[value]}
onValueChange={onSliderValueChange}
step={step}
min={min}
max={max}
>
<SliderTrack className="bg-lightGrey dark:bg-offBlack">
<SliderRange className="!bg-black dark:!bg-white" />
</SliderTrack>
<SliderThumb />
</SliderRoot>
<div
data-testid="percentage-selector"
className="flex w-full justify-between text-black dark:text-white mb-6"
>
{sizeRatios.map((size, index) => {
const proportionalSize = size ? (size / 100) * max : min;
return (
<button
className="no-underline hover:underline text-blue"
onClick={() => onButtonValueChange(proportionalSize)}
type="button"
key={index}
>
{getSizeLabel(size)}
</button>
);
})}
</div>
<dl className="text-black dark:text-white">
<div className="flex items-center justify-between">
<dt>{t('Contracts')}</dt>
<dd className="flex justify-end w-full">
<FormGroup
hideLabel={true}
label="Enter Size"
labelFor="trade-size-input"
className="mb-1"
>
<InputSetter
id="input-order-size-market"
type="number"
step={step}
min={min}
max={max}
className="w-full"
value={inputValue}
onChange={onInputValueChange}
>
{inputValue}
</InputSetter>
</FormGroup>
</dd>
</div>
</dl>
</div>
);
};
@@ -1,54 +0,0 @@
import { DealTicketEstimates } from '@vegaprotocol/deal-ticket';
import { DealTicketSizeInput } from './deal-ticket-size-input';
interface DealTicketSizeProps {
step: number;
min: number;
max: number;
size: number;
onSizeChange: (value: number) => void;
name: string;
quoteName: string;
price: string;
estCloseOut: string;
estMargin: string;
fees: string;
positionDecimalPlaces: number;
notionalSize: string;
}
export const DealTicketSize = ({
step,
min,
max,
price,
quoteName,
size,
onSizeChange,
estCloseOut,
positionDecimalPlaces,
fees,
notionalSize,
}: DealTicketSizeProps) => {
return max === 0 ? (
<p>Not enough balance to trade</p>
) : (
<div>
<DealTicketSizeInput
step={step}
min={min}
max={max}
value={size}
onValueChange={onSizeChange}
positionDecimalPlaces={positionDecimalPlaces}
/>
<DealTicketEstimates
quoteName={quoteName}
fees={fees}
estCloseOut={estCloseOut}
price={price}
notionalSize={notionalSize}
/>
</div>
);
};
@@ -1,112 +0,0 @@
import React, { useCallback, useState } from 'react';
import { t } from '@vegaprotocol/react-helpers';
import {
Dialog,
Icon,
Intent,
Tooltip,
TrafficLight,
} from '@vegaprotocol/ui-toolkit';
import { InputSetter } from '../../components/input-setter';
import { IconNames } from '@blueprintjs/icons';
import {
DataTitle,
ValueTooltipRow,
EST_SLIPPAGE,
} from '@vegaprotocol/deal-ticket';
interface DealTicketSlippageProps {
step?: number;
min?: number;
max?: number;
value: number;
onValueChange(value: number): void;
}
export const DealTicketSlippage = ({
value,
step = 0.01,
min = 0,
max = 50,
onValueChange,
}: DealTicketSlippageProps) => {
const [isDialogVisible, setIsDialogVisible] = useState(false);
const onChange = useCallback(
(event: React.ChangeEvent<HTMLInputElement>) => {
const value = event.target.value;
const numericValue = parseFloat(value);
onValueChange(numericValue);
},
[onValueChange]
);
const toggleDialog = useCallback(() => {
setIsDialogVisible(!isDialogVisible);
}, [isDialogVisible]);
const formLabel = (
<label className="flex items-center mb-1">
<span className="mr-1">{t('Adjust slippage tolerance')}</span>
<Tooltip align="center" description={EST_SLIPPAGE}>
<div className="cursor-help" tabIndex={-1}>
<Icon
name={IconNames.ISSUE}
className="block rotate-180"
ariaLabel={EST_SLIPPAGE}
/>
</div>
</Tooltip>
</label>
);
return (
<>
<Dialog
open={isDialogVisible}
onChange={toggleDialog}
intent={Intent.None}
title={t('Transaction Settings')}
>
<div data-testid="slippage-dialog">
{formLabel}
<InputSetter
id="input-order-slippage"
isInputVisible
hasError={!value}
type="number"
step={step}
min={min}
max={max}
className="w-full"
value={value}
onChange={onChange}
>
{value}%
</InputSetter>
</div>
</Dialog>
<dl className="text-black dark:text-white">
<div className="flex justify-between mb-2">
<DataTitle>{t('Est. Price Impact / Slippage')}</DataTitle>
<div className="flex">
<div className="mr-1">
<ValueTooltipRow description={EST_SLIPPAGE}>
<TrafficLight value={value} q1={1} q2={5}>
{value}%
</TrafficLight>
</ValueTooltipRow>
</div>
<button type="button" onClick={toggleDialog}>
<Icon
name={IconNames.COG}
className="block rotate-180"
ariaLabel={t('Override slippage value')}
/>
</button>
</div>
</div>
</dl>
</>
);
};
@@ -1,342 +0,0 @@
import { useCallback, useEffect, useMemo, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { useForm, Controller } from 'react-hook-form';
import { Stepper } from '../stepper';
import {
getDefaultOrder,
useOrderCloseOut,
useOrderMargin,
useMaximumPositionSize,
useCalculateSlippage,
validateAmount,
} from '@vegaprotocol/deal-ticket';
import { InputError } from '@vegaprotocol/ui-toolkit';
import { BigNumber } from 'bignumber.js';
import { MarketSelector } from '@vegaprotocol/deal-ticket';
import type { OrderSubmissionBody } from '@vegaprotocol/wallet';
import { useVegaWallet } from '@vegaprotocol/wallet';
import { VegaTxStatus } from '@vegaprotocol/wallet';
import {
t,
toDecimal,
removeDecimal,
addDecimalsFormatNumber,
addDecimal,
formatNumber,
} from '@vegaprotocol/react-helpers';
import {
useOrderSubmit,
getOrderDialogTitle,
getOrderDialogIntent,
getOrderDialogIcon,
OrderFeedback,
} from '@vegaprotocol/orders';
import { DealTicketSize } from './deal-ticket-size';
import MarketNameRenderer from '../simple-market-list/simple-market-renderer';
import SideSelector, { SIDE_NAMES } from './side-selector';
import ReviewTrade from './review-trade';
import * as Schema from '@vegaprotocol/types';
import { DealTicketSlippage } from './deal-ticket-slippage';
import { useOrderValidation } from './use-order-validation';
import type { MarketDealTicket } from '@vegaprotocol/market-list';
interface DealTicketMarketProps {
market: MarketDealTicket;
}
export const DealTicketSteps = ({ market }: DealTicketMarketProps) => {
const navigate = useNavigate();
const setMarket = useCallback(
(marketId: string) => {
navigate(`/trading/${marketId}`);
},
[navigate]
);
const {
control,
handleSubmit,
watch,
setValue,
formState: { errors },
} = useForm<OrderSubmissionBody['orderSubmission']>({
mode: 'onChange',
defaultValues: getDefaultOrder(market),
});
const emptyString = ' - ';
const step = toDecimal(market.positionDecimalPlaces);
const order = watch();
const { pubKey } = useVegaWallet();
const { message: invalidText, isDisabled } = useOrderValidation({
market,
order,
fieldErrors: errors,
});
const { submit, transaction, finalizedOrder, Dialog } = useOrderSubmit();
const maxTrade = useMaximumPositionSize({
marketId: market.id,
settlementAssetId:
market.tradableInstrument.instrument.product.settlementAsset.id,
price: market?.depth?.lastTrade?.price,
order,
});
const estCloseOut = useOrderCloseOut({
order,
market,
});
const slippage = useCalculateSlippage({ marketId: market.id, order });
const [slippageValue, setSlippageValue] = useState(
slippage ? parseFloat(slippage) : 0
);
const transactionStatus =
transaction.status === VegaTxStatus.Requested ||
transaction.status === VegaTxStatus.Pending
? 'pending'
: 'default';
useEffect(() => {
setSlippageValue(slippage ? parseFloat(slippage) : 0);
}, [slippage]);
const price = useMemo(() => {
if (slippage && market?.depth?.lastTrade?.price) {
const isLong = order.side === Schema.Side.SIDE_BUY;
const multiplier = new BigNumber(1)[isLong ? 'plus' : 'minus'](
parseFloat(slippage) / 100
);
return new BigNumber(market?.depth?.lastTrade?.price)
.multipliedBy(multiplier)
.toString();
}
return undefined;
}, [market?.depth?.lastTrade?.price, order.side, slippage]);
const estMargin = useOrderMargin({
order,
market,
partyId: pubKey || '',
derivedPrice: price,
});
const formattedPrice =
price && addDecimalsFormatNumber(price, market.decimalPlaces);
const notionalSize = useMemo(() => {
if (price) {
const size = new BigNumber(price).multipliedBy(order.size).toNumber();
return addDecimalsFormatNumber(size, market.decimalPlaces);
}
return null;
}, [market.decimalPlaces, order.size, price]);
const assetDecimals =
market.tradableInstrument.instrument.product.settlementAsset.decimals;
const fees = useMemo(() => {
if (estMargin?.totalFees && notionalSize) {
const percentage = new BigNumber(estMargin?.totalFees)
.dividedBy(notionalSize)
.multipliedBy(100)
.decimalPlaces(2)
.toString();
return `${addDecimalsFormatNumber(
estMargin.totalFees,
assetDecimals
)} (${formatNumber(addDecimal(percentage, assetDecimals), 2)}%)`;
}
return null;
}, [assetDecimals, estMargin?.totalFees, notionalSize]);
const max = useMemo(() => {
return new BigNumber(maxTrade)
.decimalPlaces(market.positionDecimalPlaces)
.toNumber();
}, [market.positionDecimalPlaces, maxTrade]);
useEffect(() => {
setSlippageValue(slippage ? parseFloat(slippage) : 0);
}, [slippage]);
const onSizeChange = useCallback(
(value: number) => {
const newVal = new BigNumber(value)
.decimalPlaces(market.positionDecimalPlaces)
.toString();
const isValid = validateAmount(step, 'Size')(newVal);
if (isValid !== 'step') {
setValue('size', newVal);
}
},
[market.positionDecimalPlaces, setValue, step]
);
const onSlippageChange = useCallback(
(value: number) => {
if (market?.depth?.lastTrade?.price) {
if (value) {
const isLong = order.side === Schema.Side.SIDE_BUY;
const multiplier = new BigNumber(1)[isLong ? 'plus' : 'minus'](
value / 100
);
const bestAskPrice = new BigNumber(market?.depth?.lastTrade?.price)
.multipliedBy(multiplier)
.decimalPlaces(market.decimalPlaces)
.toString();
setValue('price', bestAskPrice);
if (order.type === Schema.OrderType.TYPE_MARKET) {
setValue('type', Schema.OrderType.TYPE_LIMIT);
}
} else {
setValue('type', Schema.OrderType.TYPE_MARKET);
setValue('price', market?.depth?.lastTrade?.price);
}
}
setSlippageValue(value);
},
[
market.decimalPlaces,
market?.depth?.lastTrade?.price,
order.side,
order.type,
setSlippageValue,
setValue,
]
);
const onSubmit = useCallback(
(order: OrderSubmissionBody['orderSubmission']) => {
if (transactionStatus !== 'pending') {
submit({
...order,
price:
order.price && removeDecimal(order.price, market.decimalPlaces),
size: removeDecimal(order.size, market.positionDecimalPlaces),
});
}
},
[
transactionStatus,
submit,
market.decimalPlaces,
market.positionDecimalPlaces,
]
);
const steps = [
{
label: t('Select Market'),
component: (
<MarketSelector
market={market}
setMarket={setMarket}
ItemRenderer={MarketNameRenderer}
/>
),
value: market.tradableInstrument.instrument.name,
},
{
label: t('Select Direction'),
component: (
<Controller
name="side"
control={control}
render={({ field }) => (
<SideSelector value={field.value} onSelect={field.onChange} />
)}
/>
),
value: SIDE_NAMES[order.side] || '',
},
{
label: t('Choose Position Size'),
component:
max !== null ? (
<>
<DealTicketSize
step={step}
min={step}
max={max}
onSizeChange={onSizeChange}
size={new BigNumber(order.size).toNumber()}
name="size"
price={formattedPrice || emptyString}
positionDecimalPlaces={market.positionDecimalPlaces}
quoteName={
market.tradableInstrument.instrument.product.settlementAsset
.symbol
}
notionalSize={notionalSize || emptyString}
estCloseOut={estCloseOut || emptyString}
fees={fees || emptyString}
estMargin={estMargin?.margin || emptyString}
/>
<DealTicketSlippage
value={slippageValue}
onValueChange={onSlippageChange}
/>
</>
) : (
t('Loading...')
),
value: order.size,
},
{
label: t('Review Trade'),
component: (
<div className="mb-8">
{invalidText && (
<div className="mb-2">
<InputError data-testid="dealticket-error-message">
{invalidText}
</InputError>
</div>
)}
<ReviewTrade
market={market}
isDisabled={isDisabled}
transactionStatus={transactionStatus}
order={order}
estCloseOut={estCloseOut || emptyString}
estMargin={estMargin?.margin || emptyString}
price={formattedPrice || emptyString}
quoteName={
market.tradableInstrument.instrument.product.settlementAsset
.symbol
}
notionalSize={notionalSize || emptyString}
fees={fees || emptyString}
slippage={slippageValue}
/>
<Dialog
title={getOrderDialogTitle(finalizedOrder?.status)}
intent={getOrderDialogIntent(finalizedOrder?.status)}
icon={getOrderDialogIcon(finalizedOrder?.status)}
content={{
Complete: (
<OrderFeedback
transaction={transaction}
order={finalizedOrder}
/>
),
}}
/>
</div>
),
disabled: true,
},
];
return (
<form onSubmit={handleSubmit(onSubmit)} className="px-2 py-4">
<Stepper steps={steps} />
</form>
);
};
@@ -1,2 +0,0 @@
export * from './deal-ticket-container';
export * from './deal-ticket-size';
@@ -1,105 +0,0 @@
import { t } from '@vegaprotocol/react-helpers';
import {
Button,
KeyValueTable,
KeyValueTableRow,
} from '@vegaprotocol/ui-toolkit';
import classNames from 'classnames';
import { DealTicketEstimates } from '@vegaprotocol/deal-ticket';
import type { OrderSubmissionBody } from '@vegaprotocol/wallet';
import { SIDE_NAMES } from './side-selector';
import * as Schema from '@vegaprotocol/types';
import { MarketExpires } from '@vegaprotocol/market-info';
import type { MarketDealTicket } from '@vegaprotocol/market-list';
import { useMarketTagsQuery } from './__generated__/MarketTags';
interface Props {
market: MarketDealTicket;
isDisabled: boolean;
transactionStatus?: string;
order: OrderSubmissionBody['orderSubmission'];
estCloseOut: string;
estMargin: string;
quoteName: string;
price: string;
fees: string;
notionalSize: string;
slippage: number;
}
export default ({
isDisabled,
market,
order,
transactionStatus,
estCloseOut,
quoteName,
fees,
price,
notionalSize,
slippage,
}: Props) => {
const { data: tagsData } = useMarketTagsQuery({
variables: { marketId: market.id },
});
return (
<div className="mb-8 text-black dark:text-white" data-testid="review-trade">
<KeyValueTable>
<KeyValueTableRow noBorder>
<div className="flex flex-none gap-x-2 items-center">
<div
className={classNames(
{
'buyButton dark:buyButtonDark':
order.side === Schema.Side.SIDE_BUY,
'sellButton dark:sellButtonDark':
order.side === Schema.Side.SIDE_SELL,
},
'px-2 py-1 inline text-ui-small'
)}
>
{SIDE_NAMES[order.side]}
</div>
<div>{market.tradableInstrument.instrument.product.quoteName}</div>
<div>
{tagsData?.market?.tradableInstrument.instrument.metadata
.tags && (
<MarketExpires
tags={
tagsData?.market.tradableInstrument.instrument.metadata.tags
}
/>
)}
</div>
</div>
<div className="text-blue">
{`@ ${price} `}
<span className="text-ui-small inline">(EST)</span>
</div>
</KeyValueTableRow>
</KeyValueTable>
<DealTicketEstimates
size={order.size}
quoteName={quoteName}
fees={fees}
estCloseOut={estCloseOut}
notionalSize={notionalSize}
slippage={slippage.toString()}
/>
<div className="mt-12 max-w-sm">
<Button
fill={true}
type="submit"
disabled={transactionStatus === 'pending' || isDisabled}
data-testid="place-order"
rightIcon="arrow-top-right"
>
{transactionStatus === 'pending' ? t('Pending...') : t('Submit')}
</Button>
</div>
</div>
);
};
@@ -1,60 +0,0 @@
import React from 'react';
import classNames from 'classnames';
import { FormGroup } from '@vegaprotocol/ui-toolkit';
import { t } from '@vegaprotocol/react-helpers';
import * as Schema from '@vegaprotocol/types';
interface SideSelectorProps {
value: Schema.Side;
onSelect: (side: Schema.Side) => void;
}
export const SIDE_NAMES: Record<Schema.Side, string> = {
[Schema.Side.SIDE_BUY]: t('Long'),
[Schema.Side.SIDE_SELL]: t('Short'),
};
export default ({ value, onSelect }: SideSelectorProps) => {
return (
<FormGroup
label={t('Direction')}
labelFor="order-side-toggle"
hideLabel={true}
>
<fieldset
className="w-full grid md:grid-cols-2 gap-4"
id="order-side-toggle"
>
<button
aria-label={t('Open long position')}
type="button"
className={classNames(
'px-8 py-2',
'buyButton hover:buyButton dark:buyButtonDark dark:hover:buyButtonDark',
{ selected: value === Schema.Side.SIDE_BUY }
)}
onClick={() => onSelect(Schema.Side.SIDE_BUY)}
>
{t('Long')}
</button>
<button
aria-label={t('Open short position')}
type="button"
className={classNames(
'px-8 py-2',
'sellButton hover:sellButton dark:sellButtonDark dark:hover:sellButtonDark',
{ selected: value === Schema.Side.SIDE_SELL }
)}
onClick={() => onSelect(Schema.Side.SIDE_SELL)}
>
{t('Short')}
</button>
<div className="md:col-span-2 text-black dark:text-white text-ui-small">
{t(
'Trading derivatives allows you to make a profit or loss regardless of whether the market you are trading goes up or down. If you open a "long" position, you will make a profit if the price of your chosen market goes up, and you will make a profit for "short" positions when the price goes down.'
)}
</div>
</fieldset>
</FormGroup>
);
};
@@ -1,415 +0,0 @@
import * as React from 'react';
import { renderHook } from '@testing-library/react';
import { useVegaWallet } from '@vegaprotocol/wallet';
import { MockedProvider } from '@apollo/client/testing';
import type { VegaWalletContextShape } from '@vegaprotocol/wallet';
import * as Schema from '@vegaprotocol/types';
import type { ValidationProps } from './use-order-validation';
import { marketTranslations, useOrderValidation } from './use-order-validation';
import type { MarketDealTicket } from '@vegaprotocol/market-list';
import * as DealTicket from '@vegaprotocol/deal-ticket';
jest.mock('@vegaprotocol/wallet');
jest.mock('@vegaprotocol/deal-ticket', () => {
return {
...jest.requireActual('@vegaprotocol/deal-ticket'),
useOrderMarginValidation: jest.fn(),
};
});
type SettlementAsset =
MarketDealTicket['tradableInstrument']['instrument']['product']['settlementAsset'];
const asset: SettlementAsset = {
__typename: 'Asset',
id: 'asset-id',
symbol: 'asset-symbol',
name: 'asset-name',
decimals: 2,
};
const market: MarketDealTicket = {
id: 'market-id',
decimalPlaces: 2,
positionDecimalPlaces: 1,
tradingMode: Schema.MarketTradingMode.TRADING_MODE_CONTINUOUS,
state: Schema.MarketState.STATE_ACTIVE,
tradableInstrument: {
__typename: 'TradableInstrument',
instrument: {
__typename: 'Instrument',
id: 'instrument-id',
name: 'instrument-name',
code: 'instriment-code',
metadata: {
tags: [],
},
product: {
__typename: 'Future',
quoteName: 'quote-name',
settlementAsset: asset,
dataSourceSpecForTradingTermination: {
id: 'dataSource-id',
},
},
},
},
depth: {
__typename: 'MarketDepth',
lastTrade: {
__typename: 'Trade',
price: '100',
},
},
fees: {
__typename: 'Fees',
factors: {
__typename: 'FeeFactors',
makerFee: '1',
infrastructureFee: '2',
liquidityFee: '3',
},
},
data: {
__typename: 'MarketData',
bestBidPrice: '1605489971',
bestOfferPrice: '1606823730',
markPrice: '1606823730',
trigger: Schema.AuctionTrigger.AUCTION_TRIGGER_UNSPECIFIED,
staticMidPrice: '1606156850',
marketTradingMode: Schema.MarketTradingMode.TRADING_MODE_CONTINUOUS,
marketState: Schema.MarketState.STATE_ACTIVE,
indicativeVolume: '0',
indicativePrice: '0',
bestStaticBidPrice: '1605489971',
bestStaticOfferPrice: '1606823730',
targetStake: '8561302732',
suppliedStake: '727654170336',
auctionStart: null,
auctionEnd: null,
market: { __typename: 'Market', id: 'market-id' },
},
marketTimestamps: {
__typename: 'MarketTimestamps',
close: null,
open: null,
},
};
const defaultWalletContext = {
pubKey: '111111__111111',
pubKeys: [],
sendTx: jest.fn().mockReturnValue(Promise.resolve(null)),
connect: jest.fn(),
disconnect: jest.fn(),
selectPubKey: jest.fn(),
connector: null,
};
const order = {
type: Schema.OrderType.TYPE_MARKET,
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_FOK,
marketId: 'market-id',
side: Schema.Side.SIDE_BUY,
size: '0.1',
};
const defaultOrder = {
market: { ...market },
step: 0.1,
order: {
...order,
},
};
const ERROR = {
KEY_MISSING: 'No public key selected',
KEY_TAINTED: 'Selected public key has been tainted',
MARKET_SUSPENDED: 'Market is currently suspended',
MARKET_INACTIVE: 'Market is no longer active',
MARKET_WAITING: 'Market is not active yet',
MARKET_CONTINUOUS_LIMIT:
'Only limit orders are permitted when market is in auction',
MARKET_CONTINUOUS_TIF:
'Until the auction ends, you can only place GFA, GTT, or GTC limit orders',
FIELD_SIZE_REQ: 'You need to provide a size',
FIELD_SIZE_MIN: `Size cannot be lower than "${defaultOrder.step}"`,
FIELD_PRICE_REQ: 'You need to provide a price',
FIELD_PRICE_MIN: 'The price cannot be negative',
FIELD_PRICE_STEP_NULL: 'Order sizes must be in whole numbers for this market',
FIELD_PRICE_STEP_DECIMAL: `The size field accepts up to ${market.positionDecimalPlaces} decimal places`,
};
function setup(
props?: Partial<ValidationProps>,
context?: Partial<VegaWalletContextShape>
) {
const mockUseVegaWallet = useVegaWallet as jest.Mock;
mockUseVegaWallet.mockReturnValue({ ...defaultWalletContext, context });
return renderHook(() => useOrderValidation({ ...defaultOrder, ...props }), {
wrapper: MockedProvider,
});
}
describe('useOrderValidation', () => {
afterEach(() => {
jest.clearAllMocks();
});
it('Returns empty string when given valid data', () => {
jest.spyOn(DealTicket, 'useOrderMarginValidation').mockReturnValue({
balance: '0',
margin: '100',
balanceError: false,
});
const { result } = setup();
expect(result.current).toStrictEqual({
isDisabled: false,
message: ``,
section: '',
});
});
it('Returns an error message when no keypair found', () => {
jest.spyOn(DealTicket, 'useOrderMarginValidation').mockReturnValue({
balance: '0',
margin: '100',
balanceError: false,
});
const { result } = setup(defaultOrder, { pubKey: null });
expect(result.current).toStrictEqual({
isDisabled: false,
message: ``,
section: '',
});
});
it.each`
state
${Schema.MarketState.STATE_SETTLED}
${Schema.MarketState.STATE_REJECTED}
${Schema.MarketState.STATE_TRADING_TERMINATED}
${Schema.MarketState.STATE_CLOSED}
${Schema.MarketState.STATE_CANCELLED}
`(
'Returns an error message for market state when not accepting orders',
({ state }) => {
const market = {
...defaultOrder.market,
data: { ...defaultOrder.market.data, marketState: state },
};
const { result } = setup({ market });
expect(result.current).toStrictEqual({
isDisabled: true,
message: `This market is ${marketTranslations(
state
)} and not accepting orders`,
section: 'sec-summary',
});
}
);
it.each`
state
${Schema.MarketState.STATE_PENDING}
${Schema.MarketState.STATE_PROPOSED}
`(
'Returns an error message for market state suspended or pending',
({ state }) => {
jest.spyOn(DealTicket, 'useOrderMarginValidation').mockReturnValue({
balance: '0',
margin: '100',
balanceError: false,
});
const market = {
...defaultOrder.market,
data: {
...defaultOrder.market.data,
marketState: state,
marketTradingMode:
Schema.MarketTradingMode.TRADING_MODE_BATCH_AUCTION,
},
};
const { result } = setup({
market,
order: {
...order,
type: Schema.OrderType.TYPE_LIMIT,
timeInForce: Schema.OrderTimeInForce.TIME_IN_FORCE_GTT,
},
});
expect(result.current).toStrictEqual({
isDisabled: false,
message: `This market is ${Schema.MarketStateMapping[
state as Schema.MarketState
].toLowerCase()} and only accepting liquidity commitment orders`,
section: 'sec-summary',
});
}
);
it.each`
tradingMode | errorMessage
${Schema.MarketTradingMode.TRADING_MODE_BATCH_AUCTION} | ${ERROR.MARKET_CONTINUOUS_LIMIT}
${Schema.MarketTradingMode.TRADING_MODE_MONITORING_AUCTION} | ${ERROR.MARKET_CONTINUOUS_LIMIT}
${Schema.MarketTradingMode.TRADING_MODE_OPENING_AUCTION} | ${ERROR.MARKET_CONTINUOUS_LIMIT}
`(
`Returns an error message when trying to submit a non-limit order for a "$tradingMode" market`,
({ tradingMode, errorMessage }) => {
const market = {
...defaultOrder.market,
data: { ...defaultOrder.market.data, marketTradingMode: tradingMode },
};
const { result } = setup({
market,
order: {
...order,
type: Schema.OrderType.TYPE_MARKET,
},
});
expect(result.current.isDisabled).toBeTruthy();
expect(result.current.message).toBe(errorMessage);
}
);
it.each`
tradingMode | orderTimeInForce | errorMessage
${Schema.MarketTradingMode.TRADING_MODE_BATCH_AUCTION} | ${Schema.OrderTimeInForce.TIME_IN_FORCE_FOK} | ${ERROR.MARKET_CONTINUOUS_TIF}
${Schema.MarketTradingMode.TRADING_MODE_MONITORING_AUCTION} | ${Schema.OrderTimeInForce.TIME_IN_FORCE_FOK} | ${ERROR.MARKET_CONTINUOUS_TIF}
${Schema.MarketTradingMode.TRADING_MODE_OPENING_AUCTION} | ${Schema.OrderTimeInForce.TIME_IN_FORCE_FOK} | ${ERROR.MARKET_CONTINUOUS_TIF}
${Schema.MarketTradingMode.TRADING_MODE_BATCH_AUCTION} | ${Schema.OrderTimeInForce.TIME_IN_FORCE_IOC} | ${ERROR.MARKET_CONTINUOUS_TIF}
${Schema.MarketTradingMode.TRADING_MODE_MONITORING_AUCTION} | ${Schema.OrderTimeInForce.TIME_IN_FORCE_IOC} | ${ERROR.MARKET_CONTINUOUS_TIF}
${Schema.MarketTradingMode.TRADING_MODE_OPENING_AUCTION} | ${Schema.OrderTimeInForce.TIME_IN_FORCE_IOC} | ${ERROR.MARKET_CONTINUOUS_TIF}
${Schema.MarketTradingMode.TRADING_MODE_BATCH_AUCTION} | ${Schema.OrderTimeInForce.TIME_IN_FORCE_GFN} | ${ERROR.MARKET_CONTINUOUS_TIF}
${Schema.MarketTradingMode.TRADING_MODE_MONITORING_AUCTION} | ${Schema.OrderTimeInForce.TIME_IN_FORCE_GFN} | ${ERROR.MARKET_CONTINUOUS_TIF}
${Schema.MarketTradingMode.TRADING_MODE_OPENING_AUCTION} | ${Schema.OrderTimeInForce.TIME_IN_FORCE_GFN} | ${ERROR.MARKET_CONTINUOUS_TIF}
`(
`Returns an error message when submitting a limit order with a "$orderTimeInForce" value to a "$tradingMode" market`,
({ tradingMode, orderTimeInForce, errorMessage }) => {
const market = {
...defaultOrder.market,
data: { ...defaultOrder.market.data, marketTradingMode: tradingMode },
};
const { result } = setup({
market,
order: {
...order,
type: Schema.OrderType.TYPE_LIMIT,
timeInForce: orderTimeInForce,
},
});
expect(result.current).toStrictEqual({
isDisabled: true,
message: errorMessage,
section: 'sec-force',
});
}
);
it.each`
fieldName | errorType | section | errorMessage
${`size`} | ${`required`} | ${'sec-size'} | ${ERROR.FIELD_SIZE_REQ}
${`size`} | ${`min`} | ${'sec-size'} | ${ERROR.FIELD_SIZE_MIN}
${`price`} | ${`required`} | ${'sec-price'} | ${ERROR.FIELD_PRICE_REQ}
${`price`} | ${`min`} | ${'sec-price'} | ${ERROR.FIELD_PRICE_MIN}
`(
`Returns an error message when the order $fieldName "$errorType" validation fails`,
({ fieldName, errorType, section, errorMessage }) => {
const { result } = setup({
fieldErrors: { [fieldName]: { type: errorType } },
order: {
...order,
type: Schema.OrderType.TYPE_LIMIT,
},
});
expect(result.current).toStrictEqual({
isDisabled: true,
message: errorMessage,
section,
});
}
);
it('Returns an error message when the order size incorrectly has decimal values', () => {
const { result } = setup({
market: { ...market, positionDecimalPlaces: 0 },
fieldErrors: {
size: { type: `validate`, message: DealTicket.ERROR_SIZE_DECIMAL },
},
});
expect(result.current).toStrictEqual({
isDisabled: true,
message: ERROR.FIELD_PRICE_STEP_NULL,
section: 'sec-size',
});
});
it('Returns an error message when the order size has more decimals than allowed', () => {
const { result } = setup({
fieldErrors: {
size: { type: `validate`, message: DealTicket.ERROR_SIZE_DECIMAL },
},
});
expect(result.current).toStrictEqual({
isDisabled: true,
message: ERROR.FIELD_PRICE_STEP_DECIMAL,
section: 'sec-size',
});
});
it('Returns an error message when the estimated margin is higher than collateral', async () => {
const invalidatedMockValue = {
balance: '100',
margin: '200',
balanceError: true,
};
jest
.spyOn(DealTicket, 'useOrderMarginValidation')
.mockReturnValue(invalidatedMockValue);
const { result } = setup({});
expect(result.current.isDisabled).toBe(false);
const testElement = (
<DealTicket.MarginWarning
margin={invalidatedMockValue.margin}
balance={invalidatedMockValue.balance}
asset={asset}
/>
);
expect((result.current.message as React.ReactElement)?.props).toEqual(
testElement.props
);
expect((result.current.message as React.ReactElement)?.type).toEqual(
testElement.type
);
});
it.each`
state
${Schema.MarketState.STATE_PENDING}
${Schema.MarketState.STATE_PROPOSED}
`(
'Returns error when market state is pending and size is wrong',
({ state }) => {
const market = {
...defaultOrder.market,
data: { ...defaultOrder.market.data, marketState: state },
};
const { result } = setup({
fieldErrors: {
size: { type: `validate`, message: DealTicket.ERROR_SIZE_DECIMAL },
},
market,
});
expect(result.current).toStrictEqual({
isDisabled: true,
message: ERROR.FIELD_PRICE_STEP_DECIMAL,
section: 'sec-size',
});
}
);
});
@@ -1,384 +0,0 @@
import type { ReactNode } from 'react';
import type { FieldErrors } from 'react-hook-form';
import { useMemo } from 'react';
import { 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,
ERROR_SIZE_DECIMAL,
useOrderMarginValidation,
} from '@vegaprotocol/deal-ticket';
import type { MarketDealTicket } from '@vegaprotocol/market-list';
export const DEAL_TICKET_SECTION = {
TYPE: 'sec-type',
SIZE: 'sec-size',
PRICE: 'sec-price',
FORCE: 'sec-force',
EXPIRY: 'sec-expiry',
SUMMARY: 'sec-summary',
};
export const ERROR_EXPIRATION_IN_THE_PAST = 'ERROR_EXPIRATION_IN_THE_PAST';
export type ValidationProps = {
step?: number;
market: MarketDealTicket;
order: OrderSubmissionBody['orderSubmission'];
fieldErrors?: FieldErrors<OrderSubmissionBody['orderSubmission']>;
};
export const marketTranslations = (marketState: Schema.MarketState) => {
switch (marketState) {
case Schema.MarketState.STATE_TRADING_TERMINATED:
return t('terminated');
default:
return t(Schema.MarketStateMapping[marketState]).toLowerCase();
}
};
export type DealTicketSection =
| ''
| typeof DEAL_TICKET_SECTION[keyof typeof DEAL_TICKET_SECTION];
export const useOrderValidation = ({
market,
fieldErrors,
order,
}: ValidationProps): {
message: ReactNode | string;
isDisabled: boolean;
section: DealTicketSection;
} => {
const { pubKey } = useVegaWallet();
const minSize = toDecimal(market.positionDecimalPlaces);
const isInvalidOrderMargin = useOrderMarginValidation({ market, order });
const fieldErrorChecking = useMemo<{
message: ReactNode | string;
isDisabled: boolean;
section: DealTicketSection;
} | null>(() => {
if (fieldErrors?.size?.type || fieldErrors?.price?.type) {
if (fieldErrors?.size?.type === 'required') {
return {
isDisabled: true,
message: t('You need to provide a size'),
section: DEAL_TICKET_SECTION.SIZE,
};
}
if (fieldErrors?.size?.type === 'min') {
return {
isDisabled: true,
message: t(`Size cannot be lower than "${minSize}"`),
section: DEAL_TICKET_SECTION.SIZE,
};
}
if (
fieldErrors?.price?.type === 'required' &&
order.type !== Schema.OrderType.TYPE_MARKET
) {
return {
isDisabled: true,
message: t('You need to provide a price'),
section: DEAL_TICKET_SECTION.PRICE,
};
}
if (
fieldErrors?.price?.type === 'min' &&
order.type !== Schema.OrderType.TYPE_MARKET
) {
return {
isDisabled: true,
message: t(`The price cannot be negative`),
section: DEAL_TICKET_SECTION.PRICE,
};
}
if (
fieldErrors?.size?.type === 'validate' &&
fieldErrors?.size?.message === ERROR_SIZE_DECIMAL
) {
if (market.positionDecimalPlaces === 0) {
return {
isDisabled: true,
message: t('Order sizes must be in whole numbers for this market'),
section: DEAL_TICKET_SECTION.SIZE,
};
}
return {
isDisabled: true,
message: t(
`The size field accepts up to ${market.positionDecimalPlaces} decimal places`
),
section: DEAL_TICKET_SECTION.SIZE,
};
}
}
if (
fieldErrors?.expiresAt?.type === 'validate' &&
fieldErrors?.expiresAt.message === ERROR_EXPIRATION_IN_THE_PAST
) {
return {
isDisabled: false,
message: t(
'The expiry date that you have entered appears to be in the past'
),
section: DEAL_TICKET_SECTION.EXPIRY,
};
}
return null;
}, [
fieldErrors?.size?.type,
fieldErrors?.size?.message,
fieldErrors?.price?.type,
fieldErrors?.expiresAt?.type,
fieldErrors?.expiresAt?.message,
order.type,
minSize,
market.positionDecimalPlaces,
]);
const { message, isDisabled, section } = useMemo<{
message: ReactNode | string;
isDisabled: boolean;
section: DealTicketSection;
}>(() => {
if (!pubKey) {
return {
message: t('No public key selected'),
isDisabled: true,
section: DEAL_TICKET_SECTION.SUMMARY,
};
}
if (
[
Schema.MarketState.STATE_SETTLED,
Schema.MarketState.STATE_REJECTED,
Schema.MarketState.STATE_TRADING_TERMINATED,
Schema.MarketState.STATE_CANCELLED,
Schema.MarketState.STATE_CLOSED,
].includes(market.data.marketState)
) {
return {
isDisabled: true,
message: t(
`This market is ${marketTranslations(
market.data.marketState
)} and not accepting orders`
),
section: DEAL_TICKET_SECTION.SUMMARY,
};
}
if (
[
Schema.MarketState.STATE_PROPOSED,
Schema.MarketState.STATE_PENDING,
].includes(market.data.marketState)
) {
if (fieldErrorChecking) {
return fieldErrorChecking;
}
return {
isDisabled: false,
message: t(
`This market is ${marketTranslations(
market.data.marketState
)} and only accepting liquidity commitment orders`
),
section: DEAL_TICKET_SECTION.SUMMARY,
};
}
if (isMarketInAuction(market)) {
if (order.type === Schema.OrderType.TYPE_MARKET) {
if (
market.data.marketTradingMode ===
Schema.MarketTradingMode.TRADING_MODE_MONITORING_AUCTION &&
market.data.trigger ===
Schema.AuctionTrigger.AUCTION_TRIGGER_LIQUIDITY
) {
return {
isDisabled: true,
message: (
<span>
{t('This market is in auction until it reaches')}{' '}
<Tooltip
description={
<MarketDataGrid grid={compileGridData(market)} />
}
>
<span>{t('sufficient liquidity')}</span>
</Tooltip>
{'. '}
{t('Only limit orders are permitted when market is in auction')}
</span>
),
section: DEAL_TICKET_SECTION.TYPE,
};
}
if (
market.data.marketTradingMode ===
Schema.MarketTradingMode.TRADING_MODE_MONITORING_AUCTION &&
market.data.trigger === Schema.AuctionTrigger.AUCTION_TRIGGER_PRICE
) {
return {
isDisabled: true,
message: (
<span>
{t('This market is in auction due to')}{' '}
<Tooltip
description={
<MarketDataGrid grid={compileGridData(market)} />
}
>
<span>{t('high price volatility')}</span>
</Tooltip>
{'. '}
{t('Only limit orders are permitted when market is in auction')}
</span>
),
section: DEAL_TICKET_SECTION.TYPE,
};
}
return {
isDisabled: true,
message: t(
'Only limit orders are permitted when market is in auction'
),
section: DEAL_TICKET_SECTION.SUMMARY,
};
}
if (
order.type === Schema.OrderType.TYPE_LIMIT &&
[
Schema.OrderTimeInForce.TIME_IN_FORCE_FOK,
Schema.OrderTimeInForce.TIME_IN_FORCE_IOC,
Schema.OrderTimeInForce.TIME_IN_FORCE_GFN,
].includes(order.timeInForce)
) {
if (
market.data.marketTradingMode ===
Schema.MarketTradingMode.TRADING_MODE_MONITORING_AUCTION &&
market.data.trigger ===
Schema.AuctionTrigger.AUCTION_TRIGGER_LIQUIDITY
) {
return {
isDisabled: true,
message: (
<span>
{t('This market is in auction until it reaches')}{' '}
<Tooltip
description={
<MarketDataGrid grid={compileGridData(market)} />
}
>
<span>{t('sufficient liquidity')}</span>
</Tooltip>
{'. '}
{t(
`Until the auction ends, you can only place GFA, GTT, or GTC limit orders`
)}
</span>
),
section: DEAL_TICKET_SECTION.FORCE,
};
}
if (
market.data.marketTradingMode ===
Schema.MarketTradingMode.TRADING_MODE_MONITORING_AUCTION &&
market.data.trigger === Schema.AuctionTrigger.AUCTION_TRIGGER_PRICE
) {
return {
isDisabled: true,
message: (
<span>
{t('This market is in auction due to')}{' '}
<Tooltip
description={
<MarketDataGrid grid={compileGridData(market)} />
}
>
<span>{t('high price volatility')}</span>
</Tooltip>
{'. '}
{t(
`Until the auction ends, you can only place GFA, GTT, or GTC limit orders`
)}
</span>
),
section: DEAL_TICKET_SECTION.FORCE,
};
}
return {
isDisabled: true,
message: t(
`Until the auction ends, you can only place GFA, GTT, or GTC limit orders`
),
section: DEAL_TICKET_SECTION.FORCE,
};
}
}
if (fieldErrorChecking) {
return fieldErrorChecking;
}
if (isInvalidOrderMargin.balanceError) {
return {
isDisabled: false,
message: (
<MarginWarning
margin={isInvalidOrderMargin.margin}
balance={isInvalidOrderMargin.balance}
asset={market.tradableInstrument.instrument.product.settlementAsset}
/>
),
section: DEAL_TICKET_SECTION.PRICE,
};
}
if (
[
Schema.MarketTradingMode.TRADING_MODE_BATCH_AUCTION,
Schema.MarketTradingMode.TRADING_MODE_MONITORING_AUCTION,
Schema.MarketTradingMode.TRADING_MODE_OPENING_AUCTION,
].includes(market.data.marketTradingMode)
) {
return {
isDisabled: false,
message: t(
'Any orders placed now will not trade until the auction ends'
),
section: DEAL_TICKET_SECTION.SUMMARY,
};
}
return {
isDisabled: false,
message: '',
section: '',
};
}, [
pubKey,
market,
fieldErrorChecking,
isInvalidOrderMargin,
order.type,
order.timeInForce,
]);
return { message, isDisabled, section };
};
@@ -1,18 +0,0 @@
import { t } from '@vegaprotocol/react-helpers';
import { Button } from '@vegaprotocol/ui-toolkit';
import { DepositDialog, useDepositDialog } from '@vegaprotocol/deposits';
/**
* Fetches data required for the Deposit page
*/
export const DepositContainer = () => {
const openDepositDialog = useDepositDialog((state) => state.open);
return (
<div>
<DepositDialog />
<Button size="sm" onClick={() => openDepositDialog()}>
{t('Make deposit')}
</Button>
</div>
);
};
@@ -1 +0,0 @@
export * from './deposits';
@@ -1,21 +0,0 @@
import * as React from 'react';
import classNames from 'classnames';
import type { ReactElement } from 'react';
interface Props {
children: ReactElement | ReactElement[];
className?: string;
}
export const DrawerContent = ({ children, className = '' }: Props) => {
const classes = classNames(
'w-full sm:w-full grow-1 overflow-hidden',
className
);
return (
<main aria-label="Page Content" className={classes}>
{children}
</main>
);
};
@@ -1,46 +0,0 @@
import * as React from 'react';
import classNames from 'classnames';
import { ButtonLink, Icon } from '@vegaprotocol/ui-toolkit';
import { IconNames } from '@blueprintjs/icons';
import type { IconName } from '@vegaprotocol/ui-toolkit';
import { useEffect, useState } from 'react';
export const enum DRAWER_TOGGLE_VARIANTS {
OPEN = 'open',
CLOSE = 'close',
}
interface Props {
onToggle: React.MouseEventHandler<HTMLButtonElement>;
variant: DRAWER_TOGGLE_VARIANTS.OPEN | DRAWER_TOGGLE_VARIANTS.CLOSE;
className?: string;
}
export const DrawerToggle = ({
onToggle,
variant = DRAWER_TOGGLE_VARIANTS.CLOSE,
className = '',
}: Props) => {
const [iconName, setIconName] = useState(IconNames.MENU);
const classes = classNames('md:hidden', className);
useEffect(() => {
if (variant === DRAWER_TOGGLE_VARIANTS.OPEN) {
setIconName(IconNames.MENU);
} else {
setIconName(IconNames.CROSS);
}
}, [variant]);
const ariaLabel = `${
variant === DRAWER_TOGGLE_VARIANTS.OPEN ? 'Open' : 'Close'
} Sidebar Navigation Menu`;
return (
<span className={classes}>
<ButtonLink aria-label={ariaLabel} onClick={onToggle}>
<Icon name={iconName as IconName} />
</ButtonLink>
</span>
);
};
@@ -1,13 +0,0 @@
import * as React from 'react';
import classNames from 'classnames';
import type { ReactElement } from 'react';
interface Props {
children: ReactElement | ReactElement[];
className?: string;
}
export const DrawerWrapper = ({ children, className = '' }: Props) => {
const classes = classNames('flex dark:bg-lite-black md:flex-row', className);
return <div className={classes}>{children}</div>;
};
@@ -1,63 +0,0 @@
import * as React from 'react';
import classNames from 'classnames';
import type { ReactElement } from 'react';
interface Props {
children?: ReactElement | ReactElement[];
isMenuOpen?: boolean;
onToggle(): void;
rtl?: boolean;
outerClasses?: string;
innerClasses?: string;
}
export const NavigationDrawer = ({
isMenuOpen = false,
onToggle,
children,
rtl,
outerClasses = '',
innerClasses = '',
}: Props) => {
const width = 'w-full md:w-auto md:min-w-[15%] shrink-0';
const position = 'absolute inset-0 h-full z-10 md:static';
const background = 'bg-black/50 dark:bg-white/50';
const flex = 'flex justify-end overflow-hidden';
const joinedClasses = [flex, width, position, background].join(' ');
const outerStyles = classNames(joinedClasses, {
visible: isMenuOpen,
'invisible md:visible': !isMenuOpen,
'flex-row-reverse': !rtl,
[outerClasses]: outerClasses,
});
const translateClose = rtl ? 'translate-x-full' : '-translate-x-full';
const innerStyles = classNames(
'w-3/4 md:w-full bg-white dark:bg-lite-black',
{
'translate-x-0 transition-transform md:transform-none': isMenuOpen,
[`${translateClose} md:transform-none`]: !isMenuOpen,
[innerClasses]: innerClasses,
}
);
return (
<aside aria-label="Sidebar Navigation Menu" className={outerStyles}>
<div
role="presentation"
aria-label="Content Overlay - Click To Close Sidebar Navigation"
className="md:hidden grow h-full"
onClick={onToggle}
/>
<div
role="group"
aria-label="Sidebar Navigation Grouped Content"
className={innerStyles}
>
{children}
</div>
</aside>
);
};
@@ -1,4 +0,0 @@
export * from './drawer';
export * from './drawer-toggle';
export * from './drawer-content';
export * from './drawer-wrapper';
@@ -1,48 +0,0 @@
import React from 'react';
const Comet = () => {
return (
<svg
viewBox="0 0 118 82"
fill="currentColor"
className="max-w-[7.5rem] mx-auto"
>
<g className="fill-black dark:fill-white">
<path d="M44.3791 67.5864H41.5859V70.3796H44.3791V67.5864Z"></path>
<path d="M47.173 64.7932V62H44.3799V64.7932V67.5863H47.173V64.7932Z"></path>
<path d="M41.5863 70.3794H36V73.1726H41.5863V70.3794Z"></path>
<path d="M44.3791 73.1719H41.5859V75.965H44.3791V73.1719Z"></path>
<path d="M47.173 75.9658H44.3799V81.5521H47.173V75.9658Z"></path>
<path d="M49.966 73.1719H47.1729V75.965H49.966V73.1719Z"></path>
<path d="M55.5521 70.3794H49.9658V73.1726H55.5521V70.3794Z"></path>
<path d="M49.966 67.5864H47.1729V70.3796H49.966V67.5864Z"></path>
<path d="M57.1876 60.564H54V63.7515H57.1876V60.564Z"></path>
<path d="M60.3751 57.3765H57.1875V60.564H60.3751V57.3765Z"></path>
<path d="M63.5626 54.1885H60.375V57.3761H63.5626V54.1885Z"></path>
<path d="M66.7501 51.001H63.5625V54.1886H66.7501V51.001Z"></path>
<path d="M69.9376 47.8135H66.75V51.0011H69.9376V47.8135Z"></path>
<path d="M73.1251 44.626H69.9375V47.8136H73.1251V44.626Z"></path>
<path d="M76.3126 41.4385H73.125V44.6261H76.3126V41.4385Z"></path>
<path d="M79.5001 38.251H76.3125V41.4386H79.5001V38.251Z"></path>
<path d="M82.6886 35.0635H79.501V38.2511H82.6886V35.0635Z"></path>
<path d="M85.8761 31.876H82.6885V35.0636H85.8761V31.876Z"></path>
<path d="M89.0636 28.688H85.876V31.8756H89.0636V28.688Z"></path>
<path d="M92.2511 25.5005H89.0635V28.6881H92.2511V25.5005Z"></path>
<path d="M95.4386 22.313H92.251V25.5006H95.4386V22.313Z"></path>
<path d="M98.6261 19.1255H95.4385V22.3131H98.6261V19.1255Z"></path>
<path d="M101.814 15.938H98.626V19.1256H101.814V15.938Z"></path>
<path d="M105.001 12.7505H101.813V15.9381H105.001V12.7505Z"></path>
<path d="M108.189 9.5625H105.001V12.7501H108.189V9.5625Z"></path>
<path d="M111.376 6.375H108.188V9.56258H111.376V6.375Z"></path>
<path d="M114.565 3.1875H111.377V6.37508H114.565V3.1875Z"></path>
<path d="M117.752 0H114.564V3.18758H117.752V0Z"></path>
<path d="M2.79316 20.793H0V23.5861H2.79316V20.793Z"></path>
<path d="M5.58612 18H2.79297V20.7932H5.58612V18Z"></path>
<path d="M5.58612 23.5859H2.79297V26.3791H5.58612V23.5859Z"></path>
<path d="M8.37909 20.793H5.58594V23.5861H8.37909V20.793Z"></path>
</g>
</svg>
);
};
export default Comet;
@@ -1,32 +0,0 @@
import React, { useContext } from 'react';
import { ThemeSwitcher } from '@vegaprotocol/ui-toolkit';
import { useVegaWalletDialogStore } from '@vegaprotocol/wallet';
import Logo from './logo';
import { VegaWalletConnectButton } from '../vega-wallet-connect-button';
import LocalContext from '../../context/local-context';
const Header = () => {
const { updateVegaWalletDialog } = useVegaWalletDialogStore((store) => ({
updateVegaWalletDialog: store.updateVegaWalletDialog,
}));
const {
vegaWalletDialog: { setManage },
} = useContext(LocalContext);
return (
<div
className="dark flex items-stretch pr-6 py-6 bg-black text-neutral-400"
data-testid="header"
>
<Logo />
<div className="flex items-center gap-2 ml-auto relative z-10">
<VegaWalletConnectButton
setConnectDialog={updateVegaWalletDialog}
setManageDialog={setManage}
/>
<ThemeSwitcher className="-my-4" />
</div>
</div>
);
};
export default Header;
@@ -1 +0,0 @@
export { default } from './header';
@@ -1,18 +0,0 @@
import React from 'react';
import { NavLink } from 'react-router-dom';
import { t } from '@vegaprotocol/react-helpers';
import { VLogo } from '@vegaprotocol/ui-toolkit';
const Logo = () => {
return (
<NavLink
className="mx-6 text-white"
aria-label={t('Go to home page')}
to="/"
>
<VLogo className="mx-6 my-2" />
</NavLink>
);
};
export default Logo;
@@ -1,33 +0,0 @@
import React from 'react';
import classNames from 'classnames';
interface Props {
width: number;
height: number;
className: string;
}
const Video = ({ width = 60, height = 60, className = '' }: Partial<Props>) => {
return (
<video
width={width}
height={height}
autoPlay
muted
loop
playsInline
className={classNames(
'absolute left-0 top-0 w-full h-full object-cover',
className
)}
poster="https://vega.xyz/static/poster-image.jpg"
>
<source
src="https://d33wubrfki0l68.cloudfront.net/2500bc5ef1b96927e0220eeb2bef0b22b87bcda1/3e0d3/static/moshed-aa65f0933af9abe9afb5e5663c9b3f68.mp4"
type="video/mp4"
/>
</video>
);
};
export default Video;
@@ -1,103 +0,0 @@
import classNames from 'classnames';
import React, { useEffect, useRef, useState } from 'react';
import { Link } from 'react-router-dom';
export interface Item {
name: string;
id: string;
url?: string;
isActive?: boolean;
color?: string;
cssClass?: string;
}
interface Props {
active?: string;
cssClass?: string[];
items: Item[];
'data-testid'?: string;
'aria-label'?: string;
}
const MenuItem = ({ id, name, url, isActive, cssClass }: Item): JSX.Element => {
if (!url) {
return <span data-testid={id}>{name}</span>;
}
return (
<Link
to={url}
aria-label={name}
className={classNames('pl-0 hover:opacity-75', cssClass, {
active: isActive,
})}
data-testid={id}
>
{name}
</Link>
);
};
const findActive = (active?: string, items?: Item[]) => {
if (!active && items?.length) {
return 0;
}
return items?.length
? items.findIndex((item) => item.id === active) || 0
: -1;
};
export const HorizontalMenu = ({
items,
active,
'data-testid': dataTestId,
'aria-label': ariaLabel,
}: Props) => {
const [activeNumber, setActiveNumber] = useState<number>(
findActive(active, items)
);
const slideContRef = useRef<HTMLUListElement | null>(null);
const [sliderStyles, setSliderStyles] = useState<Record<string, string>>({});
useEffect(() => {
setActiveNumber(findActive(active, items));
}, [active, items]);
useEffect(() => {
const contStyles = (
slideContRef.current as HTMLUListElement
).getBoundingClientRect();
const selectedStyles = (slideContRef.current as HTMLUListElement).children[
activeNumber
]?.getBoundingClientRect();
const styles: Record<string, string> = selectedStyles
? {
backgroundColor: items[activeNumber].color || '',
width: `${selectedStyles.width}px`,
left: `${selectedStyles.left - contStyles.left}px`,
}
: {};
setSliderStyles(styles);
}, [activeNumber, slideContRef, items]);
return items.length ? (
<ul
ref={slideContRef}
className="grid grid-flow-col auto-cols-min gap-4 relative pb-2 mb-2"
data-testid={dataTestId}
aria-label={ariaLabel}
>
{items.map((item, i) => (
<li key={item.id} className="md:mr-2 whitespace-nowrap">
<MenuItem {...item} isActive={i === activeNumber} />
</li>
))}
<li
className="absolute bottom-0 h-[2px] transition-left duration-300 dark:bg-white bg-black"
key="slider"
style={sliderStyles}
/>
</ul>
) : null;
};
export default HorizontalMenu;
@@ -1,2 +0,0 @@
export { default as HorizontalMenu } from './horizontal-menu';
export type { Item as HorizontalMenuItem } from './horizontal-menu';
@@ -1,51 +0,0 @@
import type { ReactElement } from 'react';
import { LiquidityIconPath } from './liquidity-icon';
import { MarketIconPath } from './market-icon';
import { TradeIconPath } from './trade-icon';
import { PortfolioIconPath } from './portfolio-icon';
interface IconProps {
name: string;
className: string;
}
interface IconSVGWrapperProps {
className: string;
children: ReactElement | ReactElement[] | null;
}
const getIconPath = (name: string): ReactElement | null => {
switch (name) {
case 'liquidity':
return <LiquidityIconPath />;
case 'market':
return <MarketIconPath />;
case 'trade':
return <TradeIconPath />;
case 'portfolio':
return <PortfolioIconPath />;
default:
return null;
}
};
const IconSVGWrapper = ({ className, children }: IconSVGWrapperProps) => {
return (
<svg
role="presentation"
className={className}
width="24"
height="24"
viewBox="0 0 24 24"
fill="currentColor"
>
{children}
</svg>
);
};
export const Icon = ({ name, className }: IconProps) => {
return (
<IconSVGWrapper className={className}>{getIconPath(name)}</IconSVGWrapper>
);
};
@@ -1 +0,0 @@
export * from './icon';
@@ -1,15 +0,0 @@
export const LiquidityIconPath = () => (
<>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M12.5268 1.46612L12 1.99999L11.4732 1.46612L12 0.946381L12.5268 1.46612ZM12 3.07542C11.8274 3.25709 11.6185 3.48044 11.3826 3.73943C10.6899 4.49987 9.76793 5.56335 8.84782 6.77789C7.92587 7.99485 7.01715 9.34862 6.34179 10.6903C5.66046 12.0439 5.25 13.3205 5.25 14.4C5.25 19.0485 8.47431 22.15 12 22.15C15.5257 22.15 18.75 19.0485 18.75 14.4C18.75 13.3205 18.3395 12.0439 17.6582 10.6903C16.9829 9.34862 16.0741 7.99485 15.1522 6.77789C14.2321 5.56335 13.3101 4.49987 12.6174 3.73943C12.3815 3.48044 12.1726 3.25709 12 3.07542ZM11.4732 1.46612C11.4734 1.46597 11.4732 1.46612 12 1.99999C12.5268 1.46612 12.5266 1.46597 12.5268 1.46612L12.5336 1.47291L12.5512 1.49036C12.5663 1.5055 12.5884 1.52759 12.6169 1.55634C12.6739 1.61384 12.7566 1.698 12.8615 1.80641C13.071 2.02319 13.3692 2.33722 13.7263 2.72931C14.4399 3.51261 15.3929 4.61164 16.3478 5.8721C17.3009 7.13013 18.2671 8.56386 18.998 10.0159C19.723 11.4561 20.25 12.9795 20.25 14.4C20.25 19.7514 16.4743 23.65 12 23.65C7.52569 23.65 3.75 19.7514 3.75 14.4C3.75 12.9795 4.27704 11.4561 5.00196 10.0159C5.73285 8.56386 6.69913 7.13013 7.65218 5.8721C8.60707 4.61164 9.56014 3.51261 10.2737 2.72931C10.6308 2.33722 10.929 2.02319 11.1385 1.80641C11.2434 1.698 11.3261 1.61384 11.3831 1.55634C11.4116 1.52759 11.4337 1.5055 11.4488 1.49036L11.4664 1.47291L11.4712 1.46817L11.4732 1.46612Z"
/>
<rect x="11.5" y="17.4" width="1" height="1" />
<rect x="12.5" y="16.4" width="1" height="1" />
<rect x="10.5" y="16.4" width="1" height="1" />
<rect x="14.5" y="15.4" width="1" height="1" />
<rect x="13.5" y="11.4" width="1" height="4" />
<rect x="9.5" y="11.4" width="1" height="5" />
</>
);
@@ -1,17 +0,0 @@
export const MarketIconPath = () => (
<>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M3.5 2H2V20.5V22H3.5H22V20.5H3.5V2Z"
/>
<rect x="5" y="15" width="2" height="2" />
<rect x="7" y="13" width="2" height="2" />
<rect x="9" y="11" width="2" height="2" />
<rect x="11" y="9" width="2" height="2" />
<rect x="13" y="11" width="2" height="2" />
<rect x="15" y="9" width="2" height="2" />
<rect x="17" y="7" width="2" height="2" />
<rect x="19" y="5" width="2" height="2" />
</>
);
@@ -1,17 +0,0 @@
export const PortfolioIconPath = () => (
<>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M8.5 3.5H15.5V6H8.5V3.5ZM7 6V3.5C7 2.67157 7.67157 2 8.5 2H15.5C16.3284 2 17 2.67157 17 3.5V6H20.5C21.3284 6 22 6.67157 22 7.5V20.5C22 21.3284 21.3284 22 20.5 22H3.5C2.67157 22 2 21.3284 2 20.5V7.5C2 6.67157 2.67157 6 3.5 6H7ZM15.5 7.5H8.5H3.5L3.5 20.5H20.5V7.5H15.5Z"
/>
<rect x="4" y="8" width="2" height="2" />
<rect x="6" y="10" width="2" height="2" />
<rect x="18" y="8" width="2" height="2" />
<rect x="16" y="10" width="2" height="2" />
<rect x="14" y="12" width="2" height="2" />
<rect x="8" y="12" width="2" height="2" />
<rect x="10" y="14" width="2" height="2" />
<rect x="12" y="14" width="2" height="2" />
</>
);
@@ -1,20 +0,0 @@
import React from 'react';
const Star = () => {
return (
<svg width="100%" height="100%" viewBox="0 0 21 21" fill="currentColor">
<g className="fill-black dark:fill-white">
<path d="M8.99996 5.99976H6V8.99972H8.99996V5.99976Z" />
<path d="M12.0009 2.99996V0H9.00098V2.99996V5.99993H12.0009V2.99996Z" />
<path d="M5.99993 9H0V12H5.99993V9Z" />
<path d="M8.99996 11.9998H6V14.9997H8.99996V11.9998Z" />
<path d="M12.0009 15H9.00098V20.9999H12.0009V15Z" />
<path d="M15 11.9998H12V14.9997H15V11.9998Z" />
<path d="M20.9999 9H15V12H20.9999V9Z" />
<path d="M15 5.99976H12V8.99972H15V5.99976Z" />
</g>
</svg>
);
};
export default Star;
@@ -1,14 +0,0 @@
export const TradeIconPath = () => (
<>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M19.3254 7.28784L14.8547 2.93099L15.7621 1.99999L21.4056 7.49983L21.8833 7.96534L21.4056 8.43085L15.7621 13.9307L14.8547 12.9997L19.3819 8.58784L1.99999 8.58784L1.99999 7.28784L19.3254 7.28784Z"
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M4.55785 16.6429L9.02855 20.9997L8.12124 21.9307L2.47767 16.4309L2 15.9654L2.47767 15.4999L8.12124 10L9.02855 10.931L4.50141 15.3429L21.8833 15.3429V16.6429L4.55785 16.6429Z"
/>
</>
);
@@ -1 +0,0 @@
export * from './input-setter';
@@ -1,64 +0,0 @@
import React from 'react';
import { render, waitFor, fireEvent } from '@testing-library/react';
import { InputSetter } from './index';
describe('InputSetter Component', () => {
it('should show the correct value and visibility based on props', async () => {
const value = 'Hello';
const isInputVisible = true;
const { getByRole } = await render(
<InputSetter
id="input-order-size-market"
type="number"
className="w-full"
value={value}
isInputVisible={isInputVisible}
onChange={() => false}
/>
);
const input = getByRole('spinbutton');
const btn = getByRole('button');
expect(input).toHaveAttribute('value', value);
expect(btn).toBeTruthy();
});
it('should toggle the visibility of the input when the button is clicked', async () => {
const value = 'Hello';
const isInputVisible = true;
const { getByRole } = await render(
<InputSetter
id="input-order-size-market"
type="number"
className="w-full"
value={value}
isInputVisible={isInputVisible}
onChange={() => false}
/>
);
const btn = getByRole('button');
fireEvent.click(btn);
await waitFor(() => getByRole('button'));
expect(getByRole('button')).toHaveTextContent(value);
});
it('should toggle the visibility of the input when the enter key is pressed', async () => {
const value = 'Hello';
const isInputVisible = true;
const { getByRole } = await render(
<InputSetter
id="input-order-size-market"
name="input-order-size-market"
type="number"
className="w-full"
value={value}
isInputVisible={isInputVisible}
onChange={() => false}
/>
);
fireEvent.keyDown(getByRole('spinbutton'), {
key: 'Enter',
});
await waitFor(() => getByRole('button'));
expect(getByRole('button')).toHaveTextContent(value);
});
});
@@ -1,55 +0,0 @@
import React, { useCallback, useState } from 'react';
import type { ReactNode } from 'react';
import { t } from '@vegaprotocol/react-helpers';
import { Input } from '@vegaprotocol/ui-toolkit';
import type { InputProps } from '@vegaprotocol/ui-toolkit';
interface InputSetterProps {
buttonLabel?: string;
isInputVisible?: boolean;
children?: ReactNode;
}
export const InputSetter = ({
buttonLabel = t('set'),
isInputVisible = false,
children,
...props
}: InputSetterProps & InputProps) => {
const [isInputToggled, setIsInputToggled] = useState(isInputVisible);
const toggleInput = useCallback(() => {
setIsInputToggled(!isInputToggled);
}, [isInputToggled]);
const onInputEnter = useCallback(
(event: React.KeyboardEvent) => {
if (event.key === 'Enter') {
event.stopPropagation();
toggleInput();
}
},
[toggleInput]
);
return isInputToggled ? (
<div className="flex items-center">
<Input {...props} onKeyDown={onInputEnter} />
<button
type="button"
className="no-underline hover:underline text-blue ml-2"
onClick={toggleInput}
>
{buttonLabel}
</button>
</div>
) : (
<button
type="button"
className="no-underline hover:underline text-blue py-1.5"
onClick={toggleInput}
>
{children || props.value}
</button>
);
};
@@ -1,40 +0,0 @@
import React, { useContext } from 'react';
import { useRoutes } from 'react-router-dom';
import {
NavigationDrawer,
DrawerWrapper,
DrawerContent,
DrawerToggle,
DRAWER_TOGGLE_VARIANTS,
} from '../drawer';
import { Nav, TabBar } from '../nav';
import { routerConfig } from '../../routes/router-config';
import LocalContext from '../../context/local-context';
export interface RouteChildProps {
name: string;
}
export const AppRouter = () => useRoutes(routerConfig);
export const Main = () => {
const {
menu: { menuOpen, onToggle },
} = useContext(LocalContext);
return (
<DrawerWrapper>
<NavigationDrawer rtl onToggle={onToggle} isMenuOpen={menuOpen}>
<DrawerToggle
onToggle={onToggle}
variant={DRAWER_TOGGLE_VARIANTS.CLOSE}
className="p-16"
/>
<Nav className="hidden md:block my-6 h-full" />
</NavigationDrawer>
<DrawerContent>
<AppRouter />
<TabBar className="md:hidden" />
</DrawerContent>
</DrawerWrapper>
);
};
@@ -1,2 +0,0 @@
export * from './nav';
export * from './tab-bar';
@@ -1,16 +0,0 @@
import React from 'react';
import { Icon } from '../icons';
interface NavItemProps {
iconName: string;
label?: string;
}
export const NavItem = ({ iconName, label }: NavItemProps) => {
return (
<div className="flex flex-col md:flex-row items-center justify-start cursor-pointer relative">
<Icon name={iconName} className="mr-2" />
<span className="text-lg">{label}</span>
</div>
);
};
@@ -1,32 +0,0 @@
import { routerConfig } from '../../routes';
import { NavLink } from 'react-router-dom';
import { NavItem } from './nav-item';
import React from 'react';
interface NavProps {
className?: string;
tabs?: boolean;
}
export const Nav = ({ className, tabs = false }: NavProps) => {
return (
<nav role={tabs ? 'tablist' : 'menu'} className={className}>
{routerConfig
.filter((r) => r.isNavItem)
.map((r) => (
<NavLink
role={tabs ? 'tab' : 'menuitem'}
key={r.name}
to={r.path}
className={({ isActive }) =>
`text-base block md:mb-10 px-12 md:text-black md:dark:text-white ${
isActive && 'text-white md:text-blue md:dark:text-blue'
}`
}
>
<NavItem iconName={r.icon} label={r.text} />
</NavLink>
))}
</nav>
);
};
@@ -1,15 +0,0 @@
import { Nav } from './nav';
import React from 'react';
interface TabBarProps {
className?: string;
}
export const TabBar = ({ className }: TabBarProps) => (
<div role="group" aria-label="Tab Bar Navigation Menu" className={className}>
<div role="presentation" className="py-[42px]" />
<div className="md:hidden fixed bottom-0 left-0 right-0 bg-black py-4 border-t border-neutral-300 dark:border-neutral-600">
<Nav tabs className="flex justify-evenly items-center" />
</div>
</div>
);
@@ -1,77 +0,0 @@
import { useMemo, useRef, useCallback } from 'react';
import { useOutletContext } from 'react-router-dom';
import type { AgGridReact } from 'ag-grid-react';
import { PriceCell, useDataProvider } from '@vegaprotocol/react-helpers';
import type { AccountFields } from '@vegaprotocol/accounts';
import { aggregatedAccountsDataProvider, getId } from '@vegaprotocol/accounts';
import type { IGetRowsParams } from 'ag-grid-community';
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
import {
AssetDetailsDialog,
useAssetDetailsDialogStore,
} from '@vegaprotocol/assets';
import { NO_DATA_MESSAGE } from '../../../constants';
import { ConsoleLiteGrid } from '../../console-lite-grid';
import { useAccountColumnDefinitions } from '.';
const AccountsManager = () => {
const { partyId = '' } = useOutletContext<{ partyId: string }>();
const { isOpen, id, setOpen } = useAssetDetailsDialogStore();
const gridRef = useRef<AgGridReact | null>(null);
const dataRef = useRef<AccountFields[] | null>(null);
const variables = useMemo(() => ({ partyId }), [partyId]);
const update = useCallback(
({ data }: { data: AccountFields[] | null }) => {
dataRef.current = data;
gridRef.current?.api?.refreshInfiniteCache();
return true;
},
[gridRef]
);
const { data, error, loading } = useDataProvider<AccountFields[], never>({
dataProvider: aggregatedAccountsDataProvider,
update,
variables,
});
const getRows = async ({
successCallback,
startRow,
endRow,
}: IGetRowsParams) => {
const rowsThisBlock = dataRef.current
? dataRef.current.slice(startRow, endRow)
: [];
const lastRow = dataRef.current?.length ?? -1;
successCallback(rowsThisBlock, lastRow);
};
const { columnDefs, defaultColDef } = useAccountColumnDefinitions();
console.log(data, loading);
return (
<>
<AsyncRenderer
loading={loading}
error={error}
data={data?.length ? data : null}
noDataMessage={NO_DATA_MESSAGE}
>
<ConsoleLiteGrid<AccountFields>
rowData={data?.length ? undefined : []}
rowModelType={data?.length ? 'infinite' : 'clientSide'}
ref={gridRef}
datasource={{ getRows }}
columnDefs={columnDefs}
defaultColDef={defaultColDef}
components={{ PriceCell }}
getRowId={({ data }) => getId(data)}
/>
</AsyncRenderer>
<AssetDetailsDialog
assetId={id}
open={isOpen}
onChange={(open) => setOpen(open)}
/>
</>
);
};
export default AccountsManager;
@@ -1,2 +0,0 @@
export { default as AccountManager } from './accounts';
export { default as useAccountColumnDefinitions } from './use-column-definitions';
@@ -1,80 +0,0 @@
import React, { useMemo } from 'react';
import { addDecimalsFormatNumber, t } from '@vegaprotocol/react-helpers';
import type { AccountFields } from '@vegaprotocol/accounts';
import { useAssetDetailsDialogStore } from '@vegaprotocol/assets';
import type { ColDef, GroupCellRendererParams } from 'ag-grid-community';
import type { VegaValueFormatterParams } from '@vegaprotocol/ui-toolkit';
const useAccountColumnDefinitions = () => {
const { open } = useAssetDetailsDialogStore();
const columnDefs: ColDef[] = useMemo(() => {
return [
{
colId: 'account-asset',
headerName: t('Asset'),
field: 'asset.symbol',
headerClass: 'uppercase justify-start',
cellClass: 'uppercase flex h-full items-center md:pl-4',
cellRenderer: ({ value, data }: GroupCellRendererParams) =>
value && value.length > 0 ? (
<div className="md:pl-4 grid h-full items-center" title={value}>
<div className="truncate min-w-0">
<button
className="hover:underline"
onClick={() => {
open(data.asset.id);
}}
>
{value}
</button>
</div>
</div>
) : (
''
),
},
{
colId: 'deposited',
headerName: t('Deposited'),
field: 'deposited',
cellRenderer: 'PriceCell',
valueFormatter: ({
value,
data,
}: VegaValueFormatterParams<AccountFields, 'deposited'>) => {
if (value && data) {
return addDecimalsFormatNumber(value, data.asset.decimals);
}
return '-';
},
},
{
colId: 'used',
headerName: t('Used'),
field: 'used',
cellRenderer: 'PriceCell',
valueFormatter: ({
value,
data,
}: VegaValueFormatterParams<AccountFields, 'used'>) => {
if (value && data) {
return addDecimalsFormatNumber(value, data.asset.decimals);
}
return '-';
},
},
];
}, [open]);
const defaultColDef = useMemo(() => {
return {
sortable: true,
unSortIcon: true,
headerClass: 'uppercase',
editable: false,
};
}, []);
return { columnDefs, defaultColDef };
};
export default useAccountColumnDefinitions;
@@ -1,35 +0,0 @@
import { t } from '@vegaprotocol/react-helpers';
export const PORTFOLIO_ASSETS = 'assets';
export const PORTFOLIO_POSITIONS = 'positions';
export const PORTFOLIO_ORDERS = 'orders';
export const PORTFOLIO_FILLS = 'fills';
export const PORTFOLIO_DEPOSITS = 'deposits';
export const PORTFOLIO_ITEMS = [
{
name: t('Assets'),
id: PORTFOLIO_ASSETS,
url: `/portfolio/${PORTFOLIO_ASSETS}`,
},
{
name: t('Positions'),
id: PORTFOLIO_POSITIONS,
url: `/portfolio/${PORTFOLIO_POSITIONS}`,
},
{
name: t('Orders'),
id: PORTFOLIO_ORDERS,
url: `/portfolio/${PORTFOLIO_ORDERS}`,
},
{
name: t('Fills'),
id: PORTFOLIO_FILLS,
url: `/portfolio/${PORTFOLIO_FILLS}`,
},
{
name: t('Deposits'),
id: PORTFOLIO_DEPOSITS,
url: `/portfolio/${PORTFOLIO_DEPOSITS}`,
},
];
@@ -1,53 +0,0 @@
import { useRef } from 'react';
import { useOutletContext } from 'react-router-dom';
import type { AgGridReact } from 'ag-grid-react';
import type { Trade } from '@vegaprotocol/fills';
import { useFillsList } from '@vegaprotocol/fills';
import type { BodyScrollEndEvent, BodyScrollEvent } from 'ag-grid-community';
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
import { ConsoleLiteGrid } from '../../console-lite-grid';
import { NO_DATA_MESSAGE } from '../../../constants';
import useColumnDefinitions from './use-column-definitions';
const FillsManager = () => {
const { partyId } = useOutletContext<{ partyId: string }>();
const { columnDefs, defaultColDef } = useColumnDefinitions({ partyId });
const gridRef = useRef<AgGridReact | null>(null);
const scrolledToTop = useRef(true);
const { data, error, loading, addNewRows, getRows } = useFillsList({
partyId,
gridRef,
scrolledToTop,
});
const onBodyScrollEnd = (event: BodyScrollEndEvent) => {
if (event.top === 0) {
addNewRows();
}
};
const onBodyScroll = (event: BodyScrollEvent) => {
scrolledToTop.current = event.top <= 0;
};
return (
<AsyncRenderer
loading={loading}
error={error}
data={data?.length ? data : null}
noDataMessage={NO_DATA_MESSAGE}
>
<ConsoleLiteGrid<Trade>
ref={gridRef}
rowModelType="infinite"
datasource={{ getRows }}
onBodyScrollEnd={onBodyScrollEnd}
onBodyScroll={onBodyScroll}
columnDefs={columnDefs}
defaultColDef={defaultColDef}
/>
</AsyncRenderer>
);
};
export default FillsManager;
@@ -1 +0,0 @@
export { default as FillsManager } from './fills';

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