Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aa7c510e44 | ||
|
|
48b1ed8ca6 |
@@ -38,16 +38,14 @@ const DialogsContainer = () => {
|
||||
export const Layout = () => {
|
||||
const isHome = Boolean(useMatch(Routes.HOME));
|
||||
const { ANNOUNCEMENTS_CONFIG_URL } = useEnvironment();
|
||||
const fixedWidthClasses = 'w-full max-w-[1500px] mx-auto';
|
||||
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
className={classNames(
|
||||
'min-h-screen',
|
||||
'max-w-[1500px] min-h-[100vh]',
|
||||
'mx-auto my-0',
|
||||
'grid grid-rows-[auto_1fr_auto] grid-cols-1',
|
||||
'border-vega-light-200 dark:border-vega-dark-200',
|
||||
'border-vega-light-200 dark:border-vega-dark-200 lg:border-l lg:border-r',
|
||||
'antialiased text-black dark:text-white',
|
||||
'overflow-hidden relative'
|
||||
)}
|
||||
@@ -61,13 +59,13 @@ export const Layout = () => {
|
||||
)}
|
||||
<Header />
|
||||
</div>
|
||||
<div className={fixedWidthClasses}>
|
||||
<div>
|
||||
<main className="p-4">
|
||||
{!isHome && <BreadcrumbsContainer className="mb-4" />}
|
||||
<Outlet />
|
||||
</main>
|
||||
</div>
|
||||
<div className={fixedWidthClasses}>
|
||||
<div>
|
||||
<Footer />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,19 +1,15 @@
|
||||
import classNames from 'classnames';
|
||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||
import type { ReactNode } from 'react';
|
||||
import { AnnouncementBanner } from '@vegaprotocol/announcements';
|
||||
import { Nav } from '../nav';
|
||||
import { Networks, useEnvironment } from '@vegaprotocol/environment';
|
||||
import React from 'react';
|
||||
|
||||
interface AppLayoutProps {
|
||||
children: ReactNode;
|
||||
}
|
||||
export const AppLayout = ({ children }: AppLayoutProps) => {
|
||||
const { VEGA_ENV, ANNOUNCEMENTS_CONFIG_URL } = useEnvironment();
|
||||
const { isReadOnly } = useVegaWallet();
|
||||
const AppLayoutClasses = classNames(
|
||||
'app w-full max-w-[1500px] mx-auto grid',
|
||||
'app w-full max-w-[1500px] mx-auto grid min-h-full',
|
||||
'border-neutral-700 lg:border-l lg:border-r',
|
||||
'lg:text-body-large',
|
||||
{
|
||||
'grid-rows-[repeat(2,min-content)_1fr_min-content]': !isReadOnly,
|
||||
@@ -21,18 +17,5 @@ export const AppLayout = ({ children }: AppLayoutProps) => {
|
||||
}
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="min-h-full">
|
||||
<div className="lg:text-body-large">
|
||||
{ANNOUNCEMENTS_CONFIG_URL && (
|
||||
<AnnouncementBanner
|
||||
app="governance"
|
||||
configUrl={ANNOUNCEMENTS_CONFIG_URL}
|
||||
/>
|
||||
)}
|
||||
<Nav theme={VEGA_ENV === Networks.TESTNET ? 'yellow' : 'dark'} />
|
||||
</div>
|
||||
<div className={AppLayoutClasses}>{children}</div>
|
||||
</div>
|
||||
);
|
||||
return <div className={AppLayoutClasses}>{children}</div>;
|
||||
};
|
||||
|
||||
@@ -1,16 +1,28 @@
|
||||
import { Networks, useEnvironment } from '@vegaprotocol/environment';
|
||||
import { ViewingAsBanner } from '@vegaprotocol/ui-toolkit';
|
||||
import { AnnouncementBanner } from '@vegaprotocol/announcements';
|
||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||
import React from 'react';
|
||||
|
||||
import { Nav } from '../nav';
|
||||
|
||||
export interface TemplateSidebarProps {
|
||||
children: React.ReactNode;
|
||||
sidebar: React.ReactNode[];
|
||||
}
|
||||
|
||||
export function TemplateSidebar({ children, sidebar }: TemplateSidebarProps) {
|
||||
const { VEGA_ENV, ANNOUNCEMENTS_CONFIG_URL } = useEnvironment();
|
||||
const { isReadOnly, pubKey, disconnect } = useVegaWallet();
|
||||
return (
|
||||
<>
|
||||
{ANNOUNCEMENTS_CONFIG_URL && (
|
||||
<AnnouncementBanner
|
||||
app="governance"
|
||||
configUrl={ANNOUNCEMENTS_CONFIG_URL}
|
||||
/>
|
||||
)}
|
||||
<Nav theme={VEGA_ENV === Networks.TESTNET ? 'yellow' : 'dark'} />
|
||||
{isReadOnly ? (
|
||||
<ViewingAsBanner pubKey={pubKey} disconnect={disconnect} />
|
||||
) : null}
|
||||
|
||||
@@ -602,7 +602,7 @@
|
||||
"tranche_end": "2023-05-06T00:00:00.000Z",
|
||||
"total_added": "8865",
|
||||
"total_removed": "362.31015740205",
|
||||
"locked_amount": "5243.2918055555557635",
|
||||
"locked_amount": "5538.613958333333793",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "33",
|
||||
@@ -4323,7 +4323,7 @@
|
||||
"tranche_end": "2023-12-05T00:00:00.000Z",
|
||||
"total_added": "86666.297",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "54788.2476184172999611065",
|
||||
"locked_amount": "55025.5466231533472612942",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "86666.297",
|
||||
@@ -4389,7 +4389,7 @@
|
||||
"tranche_end": "2023-06-01T00:00:00.000Z",
|
||||
"total_added": "2500",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "600.8763227513228",
|
||||
"locked_amount": "614.60431929181935",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "2500",
|
||||
@@ -4510,7 +4510,7 @@
|
||||
"tranche_end": "2023-09-01T00:00:00.000Z",
|
||||
"total_added": "17500",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "12910.415408615137",
|
||||
"locked_amount": "13005.4668629227055",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "12500",
|
||||
@@ -4777,7 +4777,7 @@
|
||||
"tranche_end": "2023-08-01T00:00:00.000Z",
|
||||
"total_added": "37500",
|
||||
"total_removed": "12294.731717775",
|
||||
"locked_amount": "21701.062768569675",
|
||||
"locked_amount": "21908.1203959484325",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "7500",
|
||||
@@ -5141,7 +5141,7 @@
|
||||
"tranche_end": "2023-12-05T00:00:00.000Z",
|
||||
"total_added": "129999.45",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "54738.260236187147286555",
|
||||
"locked_amount": "54975.34273543947564153",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "129999.45",
|
||||
@@ -5174,7 +5174,7 @@
|
||||
"tranche_end": "2024-04-01T00:00:00.000Z",
|
||||
"total_added": "54144.7663",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "51591.9435766059257577711",
|
||||
"locked_amount": "51739.79106068279198289418",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "54144.7663",
|
||||
@@ -5207,7 +5207,7 @@
|
||||
"tranche_end": "2023-09-03T00:00:00.000Z",
|
||||
"total_added": "62600",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "23624.00451547437818",
|
||||
"locked_amount": "23795.408143074584596",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "10000",
|
||||
@@ -5400,7 +5400,7 @@
|
||||
"tranche_end": "2023-09-17T00:00:00.000Z",
|
||||
"total_added": "5000",
|
||||
"total_removed": "0",
|
||||
"locked_amount": "2078.6821410451545",
|
||||
"locked_amount": "2092.3725266362253",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "5000",
|
||||
@@ -5941,7 +5941,7 @@
|
||||
"tranche_end": "2023-05-01T00:00:00.000Z",
|
||||
"total_added": "22500",
|
||||
"total_removed": "6871.43713545",
|
||||
"locked_amount": "1584.173572744015575",
|
||||
"locked_amount": "1708.408149171271425",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "7500",
|
||||
@@ -6425,7 +6425,7 @@
|
||||
"tranche_end": "2023-06-02T00:00:00.000Z",
|
||||
"total_added": "1939928.38",
|
||||
"total_removed": "928642.9598472029154",
|
||||
"locked_amount": "237807.5623674632953210932",
|
||||
"locked_amount": "243119.235875715365230116",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "1852091.69",
|
||||
@@ -40241,7 +40241,7 @@
|
||||
"tranche_end": "2023-06-05T00:00:00.000Z",
|
||||
"total_added": "3732368.4671",
|
||||
"total_removed": "715655.108029600523393",
|
||||
"locked_amount": "389928.657761997798045454489",
|
||||
"locked_amount": "398090.945142600518940293162",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "1998.95815",
|
||||
@@ -41634,7 +41634,7 @@
|
||||
"tranche_end": "2023-12-05T00:00:00.000Z",
|
||||
"total_added": "15870102.715470999700000001",
|
||||
"total_removed": "834257.00587199386490352",
|
||||
"locked_amount": "6682349.57025217979014250580920627858799674",
|
||||
"locked_amount": "6711292.5172348569092608533891844209570154",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "16249.93",
|
||||
@@ -48068,8 +48068,8 @@
|
||||
"tranche_start": "2021-11-05T00:00:00.000Z",
|
||||
"tranche_end": "2023-05-05T00:00:00.000Z",
|
||||
"total_added": "14597706.0446472999",
|
||||
"total_removed": "5844057.348231362114420626",
|
||||
"locked_amount": "447657.2297616420148104652270758603",
|
||||
"total_removed": "5843584.692344376939683626",
|
||||
"locked_amount": "474377.173613587991545219924406688",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "129284.449",
|
||||
@@ -48338,11 +48338,6 @@
|
||||
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
|
||||
"tx": "0x467e16d3f10ba66de4ab7452682f50266a731200be9e036c9b35692e0d447572"
|
||||
},
|
||||
{
|
||||
"amount": "472.655886985174737",
|
||||
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
|
||||
"tx": "0xca4c0571969c50f47990b214485913df8e2b7d1d92cdd6ac4c8bcc6ce760ce0b"
|
||||
},
|
||||
{
|
||||
"amount": "37462.74710421168752574",
|
||||
"user": "0x66827bCD635f2bB1779d68c46aEB16541bCA6ba8",
|
||||
@@ -51612,12 +51607,6 @@
|
||||
"tranche_id": 3,
|
||||
"tx": "0x467e16d3f10ba66de4ab7452682f50266a731200be9e036c9b35692e0d447572"
|
||||
},
|
||||
{
|
||||
"amount": "472.655886985174737",
|
||||
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
|
||||
"tranche_id": 3,
|
||||
"tx": "0xca4c0571969c50f47990b214485913df8e2b7d1d92cdd6ac4c8bcc6ce760ce0b"
|
||||
},
|
||||
{
|
||||
"amount": "1383.345213676043696",
|
||||
"user": "0x4Aa3c35F6CC2d507E5C18205ee57099A4C80B19b",
|
||||
@@ -54356,8 +54345,8 @@
|
||||
}
|
||||
],
|
||||
"total_tokens": "359123.469575",
|
||||
"withdrawn_tokens": "347720.524441911345933",
|
||||
"remaining_tokens": "11402.945133088654067"
|
||||
"withdrawn_tokens": "347247.868554926171196",
|
||||
"remaining_tokens": "11875.601020073828804"
|
||||
},
|
||||
{
|
||||
"address": "0xBdd412797c1B78535Afc5F71503b91fAbD0160fB",
|
||||
@@ -57991,8 +57980,8 @@
|
||||
"tranche_start": "2022-06-05T00:00:00.000Z",
|
||||
"tranche_end": "2023-06-05T00:00:00.000Z",
|
||||
"total_added": "472355.6199999996",
|
||||
"total_removed": "43120.0853616251849",
|
||||
"locked_amount": "61786.424749621320244693540030452",
|
||||
"total_removed": "43035.7702931331849",
|
||||
"locked_amount": "63079.785842701599708063408828024",
|
||||
"deposits": [
|
||||
{
|
||||
"amount": "3000",
|
||||
@@ -64641,11 +64630,6 @@
|
||||
"user": "0x07d1a589447395fe78bca3627Cb82F7C3310f598",
|
||||
"tx": "0x71bd2cf2152fd2175e3a63a2ba70ffc4db0d8d47c8feb493ae9de59c9164ffcf"
|
||||
},
|
||||
{
|
||||
"amount": "84.315068492",
|
||||
"user": "0x40447e8eDee2F8D0088844E35Ff7aD2Bb5fCabfb",
|
||||
"tx": "0x2aa7bdc96b05e86a7c689062112e932630e7e14b7f05534af1a5d140fc2a88c4"
|
||||
},
|
||||
{
|
||||
"amount": "19.918569252",
|
||||
"user": "0xcB555C5602cC0b2434A27d277e14Cb5C7bF4Ead1",
|
||||
@@ -76243,12 +76227,6 @@
|
||||
}
|
||||
],
|
||||
"withdrawals": [
|
||||
{
|
||||
"amount": "84.315068492",
|
||||
"user": "0x40447e8eDee2F8D0088844E35Ff7aD2Bb5fCabfb",
|
||||
"tranche_id": 5,
|
||||
"tx": "0x2aa7bdc96b05e86a7c689062112e932630e7e14b7f05534af1a5d140fc2a88c4"
|
||||
},
|
||||
{
|
||||
"amount": "89.067954084",
|
||||
"user": "0x40447e8eDee2F8D0088844E35Ff7aD2Bb5fCabfb",
|
||||
@@ -76257,8 +76235,8 @@
|
||||
}
|
||||
],
|
||||
"total_tokens": "200",
|
||||
"withdrawn_tokens": "173.383022576",
|
||||
"remaining_tokens": "26.616977424"
|
||||
"withdrawn_tokens": "89.067954084",
|
||||
"remaining_tokens": "110.932045916"
|
||||
},
|
||||
{
|
||||
"address": "0x1bAc2912394A42Cec87767327FC039f2EfBB95Dd",
|
||||
@@ -143194,11 +143172,6 @@
|
||||
"user": "0x759C9ABABA492500c4c730bEB568B5b851Dec2c7",
|
||||
"tx": "0xf4cdc0b0f6c24cb52dd0126bc6bff9c75ec715502809f9c80d675327beb4889d"
|
||||
},
|
||||
{
|
||||
"amount": "0",
|
||||
"user": "0x759C9ABABA492500c4c730bEB568B5b851Dec2c7",
|
||||
"tx": "0x11aafa8a2fb510a50d52e5d1e149c5c2027ad2c3dc2d9ef67c18d391c0331c49"
|
||||
},
|
||||
{
|
||||
"amount": "0",
|
||||
"user": "0x759C9ABABA492500c4c730bEB568B5b851Dec2c7",
|
||||
@@ -143481,12 +143454,6 @@
|
||||
"tranche_id": 9,
|
||||
"tx": "0xf4cdc0b0f6c24cb52dd0126bc6bff9c75ec715502809f9c80d675327beb4889d"
|
||||
},
|
||||
{
|
||||
"amount": "0",
|
||||
"user": "0x759C9ABABA492500c4c730bEB568B5b851Dec2c7",
|
||||
"tranche_id": 9,
|
||||
"tx": "0x11aafa8a2fb510a50d52e5d1e149c5c2027ad2c3dc2d9ef67c18d391c0331c49"
|
||||
},
|
||||
{
|
||||
"amount": "0",
|
||||
"user": "0x759C9ABABA492500c4c730bEB568B5b851Dec2c7",
|
||||
|
||||
@@ -29,10 +29,7 @@ import { LiquidityContainer } from '../liquidity/liquidity';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import type { PinnedAsset } from '@vegaprotocol/accounts';
|
||||
import { useScreenDimensions } from '@vegaprotocol/react-helpers';
|
||||
import {
|
||||
useMarketClickHandler,
|
||||
useMarketLiquidityClickHandler,
|
||||
} from '../../lib/hooks/use-market-click-handler';
|
||||
import { useMarketClickHandler } from '../../lib/hooks/use-market-click-handler';
|
||||
|
||||
type MarketDependantView =
|
||||
| typeof CandlesChartContainer
|
||||
@@ -82,7 +79,6 @@ const MarketBottomPanel = memo(
|
||||
({ marketId, pinnedAsset }: BottomPanelProps) => {
|
||||
const { screenSize } = useScreenDimensions();
|
||||
const onMarketClick = useMarketClickHandler(true);
|
||||
const onOrderTypeClick = useMarketLiquidityClickHandler(true);
|
||||
|
||||
return 'xxxl' === screenSize ? (
|
||||
<ResizableGrid proportionalLayout minSize={200}>
|
||||
@@ -98,7 +94,6 @@ const MarketBottomPanel = memo(
|
||||
<TradingViews.Orders
|
||||
marketId={marketId}
|
||||
onMarketClick={onMarketClick}
|
||||
onOrderTypeClick={onOrderTypeClick}
|
||||
enforceBottomPlaceholder
|
||||
/>
|
||||
</VegaWalletContainer>
|
||||
@@ -155,7 +150,6 @@ const MarketBottomPanel = memo(
|
||||
<TradingViews.Orders
|
||||
marketId={marketId}
|
||||
onMarketClick={onMarketClick}
|
||||
onOrderTypeClick={onOrderTypeClick}
|
||||
enforceBottomPlaceholder
|
||||
/>
|
||||
</VegaWalletContainer>
|
||||
@@ -299,7 +293,6 @@ interface TradePanelsProps {
|
||||
market: Market | null;
|
||||
onSelect: (marketId: string, metaKey?: boolean) => void;
|
||||
onMarketClick?: (marketId: string) => void;
|
||||
onOrderTypeClick?: (marketId: string) => void;
|
||||
onClickCollateral: () => void;
|
||||
pinnedAsset?: PinnedAsset;
|
||||
}
|
||||
@@ -310,16 +303,12 @@ export const TradePanels = ({
|
||||
onClickCollateral,
|
||||
pinnedAsset,
|
||||
}: TradePanelsProps) => {
|
||||
const onMarketClick = useMarketClickHandler(true);
|
||||
const onOrderTypeClick = useMarketLiquidityClickHandler(true);
|
||||
|
||||
const [view, setView] = useState<TradingView>('Candles');
|
||||
const renderView = () => {
|
||||
const Component = memo<{
|
||||
marketId: string;
|
||||
onSelect: (marketId: string, metaKey?: boolean) => void;
|
||||
onMarketClick?: (marketId: string) => void;
|
||||
onOrderTypeClick?: (marketId: string) => void;
|
||||
onClickCollateral: () => void;
|
||||
pinnedAsset?: PinnedAsset;
|
||||
}>(TradingViews[view]);
|
||||
@@ -336,8 +325,6 @@ export const TradePanels = ({
|
||||
onSelect={onSelect}
|
||||
onClickCollateral={onClickCollateral}
|
||||
pinnedAsset={pinnedAsset}
|
||||
onMarketClick={onMarketClick}
|
||||
onOrderTypeClick={onOrderTypeClick}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -19,10 +19,7 @@ import { usePageTitleStore } from '../../stores';
|
||||
import { LedgerContainer } from '@vegaprotocol/ledger';
|
||||
import { AccountsContainer } from '../../components/accounts-container';
|
||||
import { AccountHistoryContainer } from './account-history-container';
|
||||
import {
|
||||
useMarketClickHandler,
|
||||
useMarketLiquidityClickHandler,
|
||||
} from '../../lib/hooks/use-market-click-handler';
|
||||
import { useMarketClickHandler } from '../../lib/hooks/use-market-click-handler';
|
||||
|
||||
export const Portfolio = () => {
|
||||
const { updateTitle } = usePageTitleStore((store) => ({
|
||||
@@ -34,7 +31,6 @@ export const Portfolio = () => {
|
||||
}, [updateTitle]);
|
||||
|
||||
const onMarketClick = useMarketClickHandler(true);
|
||||
const onOrderTypeClick = useMarketLiquidityClickHandler(true);
|
||||
|
||||
const wrapperClasses = 'h-full max-h-full flex flex-col';
|
||||
return (
|
||||
@@ -58,10 +54,7 @@ export const Portfolio = () => {
|
||||
</Tab>
|
||||
<Tab id="orders" name={t('Orders')}>
|
||||
<VegaWalletContainer>
|
||||
<OrderListContainer
|
||||
onMarketClick={onMarketClick}
|
||||
onOrderTypeClick={onOrderTypeClick}
|
||||
/>
|
||||
<OrderListContainer onMarketClick={onMarketClick} />
|
||||
</VegaWalletContainer>
|
||||
</Tab>
|
||||
<Tab id="fills" name={t('Fills')}>
|
||||
|
||||
@@ -19,21 +19,3 @@ export const useMarketClickHandler = (replace = false) => {
|
||||
[navigate, marketId, replace, isMarketPage]
|
||||
);
|
||||
};
|
||||
|
||||
export const useMarketLiquidityClickHandler = (replace = false) => {
|
||||
const navigate = useNavigate();
|
||||
const { marketId } = useParams();
|
||||
const { pathname } = useLocation();
|
||||
const isLiquidityPage = pathname.match(/^\/liquidity\/(.+)/);
|
||||
return useCallback(
|
||||
(selectedId: string, metaKey?: boolean) => {
|
||||
const link = Links[Routes.LIQUIDITY](selectedId);
|
||||
if (metaKey) {
|
||||
window.open(`/#${link}`, '_blank');
|
||||
} else if (selectedId !== marketId || !isLiquidityPage) {
|
||||
navigate(link, { replace });
|
||||
}
|
||||
},
|
||||
[navigate, marketId, replace, isLiquidityPage]
|
||||
);
|
||||
};
|
||||
|
||||
@@ -33,8 +33,6 @@ import { ViewingBanner } from '../components/viewing-banner';
|
||||
import { Banner } from '../components/banner';
|
||||
import { AppLoader, DynamicLoader } from '../components/app-loader';
|
||||
import { Navbar } from '../components/navbar';
|
||||
import { useDataProvider } from '@vegaprotocol/react-helpers';
|
||||
import { activeOrdersProvider } from '@vegaprotocol/orders';
|
||||
|
||||
const DEFAULT_TITLE = t('Welcome to Vega trading!');
|
||||
|
||||
@@ -97,7 +95,6 @@ function AppBody({ Component }: AppProps) {
|
||||
<ToastsManager />
|
||||
<InitializeHandlers />
|
||||
<MaybeConnectEagerly />
|
||||
<PartyData />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -130,18 +127,6 @@ function VegaTradingApp(props: AppProps) {
|
||||
|
||||
export default VegaTradingApp;
|
||||
|
||||
const PartyData = () => {
|
||||
const { pubKey } = useVegaWallet();
|
||||
const variables = { partyId: pubKey || '' };
|
||||
const skip = !pubKey;
|
||||
useDataProvider({
|
||||
dataProvider: activeOrdersProvider,
|
||||
variables,
|
||||
skip,
|
||||
});
|
||||
return null;
|
||||
};
|
||||
|
||||
const MaybeConnectEagerly = () => {
|
||||
useVegaEagerConnect(Connectors);
|
||||
useEthereumEagerConnect();
|
||||
|
||||
@@ -31,7 +31,7 @@ export enum Routes {
|
||||
MARKET = '/markets',
|
||||
MARKETS = '/markets/all',
|
||||
PORTFOLIO = '/portfolio',
|
||||
LIQUIDITY = '/liquidity',
|
||||
LIQUIDITY = 'liquidity/:marketId',
|
||||
}
|
||||
|
||||
type ConsoleLinks = { [r in Routes]: (...args: string[]) => string };
|
||||
@@ -41,10 +41,8 @@ export const Links: ConsoleLinks = {
|
||||
marketId ? trimEnd(`${Routes.MARKET}/${marketId}`, '/') : Routes.MARKET,
|
||||
[Routes.MARKETS]: () => Routes.MARKETS,
|
||||
[Routes.PORTFOLIO]: () => Routes.PORTFOLIO,
|
||||
[Routes.LIQUIDITY]: (marketId: string | null | undefined) =>
|
||||
marketId
|
||||
? trimEnd(`${Routes.LIQUIDITY}/${marketId}`, '/')
|
||||
: Routes.LIQUIDITY,
|
||||
[Routes.LIQUIDITY]: (marketId: string) =>
|
||||
Routes.LIQUIDITY.replace(':marketId', marketId),
|
||||
};
|
||||
|
||||
const routerConfig: RouteObject[] = [
|
||||
@@ -72,16 +70,6 @@ const routerConfig: RouteObject[] = [
|
||||
{
|
||||
path: Routes.LIQUIDITY,
|
||||
element: <LazyLiquidity />,
|
||||
children: [
|
||||
{
|
||||
index: true,
|
||||
element: <LazyLiquidity />,
|
||||
},
|
||||
{
|
||||
path: ':marketId',
|
||||
element: <LazyLiquidity />,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: Routes.PORTFOLIO,
|
||||
|
||||
@@ -10,7 +10,6 @@ export * from './lib/cells/price-flash-cell';
|
||||
export * from './lib/cells/vol-cell';
|
||||
export * from './lib/cells/centered-grid-cell';
|
||||
export * from './lib/cells/market-name-cell';
|
||||
export * from './lib/cells/order-type-cell';
|
||||
|
||||
export * from './lib/filters/date-range-filter';
|
||||
export * from './lib/filters/set-filter';
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
import type { MouseEvent } from 'react';
|
||||
import { useMemo } from 'react';
|
||||
import { useCallback } from 'react';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import * as Schema from '@vegaprotocol/types';
|
||||
|
||||
interface OrderTypeCellProps {
|
||||
value?: Schema.OrderType;
|
||||
data?: Schema.Order;
|
||||
onClick?: (marketId: string, metaKey?: boolean) => void;
|
||||
}
|
||||
|
||||
export const OrderTypeCell = ({
|
||||
value,
|
||||
data: order,
|
||||
onClick,
|
||||
}: OrderTypeCellProps) => {
|
||||
const id = order ? order.market.id : '';
|
||||
|
||||
const label = useMemo(() => {
|
||||
if (!order) {
|
||||
return undefined;
|
||||
}
|
||||
if (!value) return '-';
|
||||
if (order?.peggedOrder) {
|
||||
return t('Pegged');
|
||||
}
|
||||
if (order?.liquidityProvision) {
|
||||
return t('Liquidity provision');
|
||||
}
|
||||
return Schema.OrderTypeMapping[value];
|
||||
}, [order, value]);
|
||||
|
||||
const handleOnClick = useCallback(
|
||||
(ev: MouseEvent<HTMLButtonElement>) => {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
if (onClick) {
|
||||
onClick(id, ev.metaKey || ev.ctrlKey);
|
||||
}
|
||||
},
|
||||
[id, onClick]
|
||||
);
|
||||
if (!order) return null;
|
||||
return order?.liquidityProvision ? (
|
||||
<button onClick={handleOnClick} tabIndex={0} className="underline">
|
||||
{label}
|
||||
</button>
|
||||
) : (
|
||||
<span>{label}</span>
|
||||
);
|
||||
};
|
||||
@@ -8,7 +8,7 @@ const commonProps = {
|
||||
|
||||
describe('DateRangeFilter', () => {
|
||||
it('should be properly rendered', async () => {
|
||||
const defaultValue = {
|
||||
const defaultRangeFilter = {
|
||||
start: '2023-02-14T13:53:01+01:00',
|
||||
end: '2023-02-21T13:53:01+01:00',
|
||||
};
|
||||
@@ -17,7 +17,7 @@ describe('DateRangeFilter', () => {
|
||||
render(
|
||||
<DateRangeFilter
|
||||
{...(commonProps as unknown as DateRangeFilterProps)}
|
||||
defaultValue={defaultValue}
|
||||
defaultRangeFilter={defaultRangeFilter}
|
||||
/>
|
||||
);
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { ChangeEvent } from 'react';
|
||||
import { useEffect, useMemo, useRef } from 'react';
|
||||
import { useEffect, useMemo } from 'react';
|
||||
import type * as Schema from '@vegaprotocol/types';
|
||||
import { forwardRef, useImperativeHandle, useState } from 'react';
|
||||
import type { IDoesFilterPassParams, IFilterParams } from 'ag-grid-community';
|
||||
@@ -17,9 +17,9 @@ import { formatForInput } from '@vegaprotocol/utils';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
import { InputError } from '@vegaprotocol/ui-toolkit';
|
||||
|
||||
const defaultValue: Schema.DateRange = {};
|
||||
const defaultFilterValue: Schema.DateRange = {};
|
||||
export interface DateRangeFilterProps extends IFilterParams {
|
||||
defaultValue?: Schema.DateRange;
|
||||
defaultRangeFilter?: Schema.DateRange;
|
||||
maxSubDays?: number;
|
||||
maxNextDays?: number;
|
||||
maxDaysRange?: number;
|
||||
@@ -27,9 +27,8 @@ export interface DateRangeFilterProps extends IFilterParams {
|
||||
|
||||
export const DateRangeFilter = forwardRef(
|
||||
(props: DateRangeFilterProps, ref) => {
|
||||
const defaultDates = props?.defaultValue || defaultValue;
|
||||
const defaultDates = props?.defaultRangeFilter || defaultFilterValue;
|
||||
const [value, setValue] = useState<Schema.DateRange>(defaultDates);
|
||||
const valueRef = useRef<Schema.DateRange>(value);
|
||||
const [error, setError] = useState<string>('');
|
||||
const [minStartDate, maxStartDate, minEndDate, maxEndDate] = useMemo(() => {
|
||||
const minStartDate =
|
||||
@@ -94,7 +93,7 @@ export const DateRangeFilter = forwardRef(
|
||||
},
|
||||
|
||||
isFilterActive() {
|
||||
return valueRef.current.start || valueRef.current.end;
|
||||
return value.start || value.end;
|
||||
},
|
||||
|
||||
getModel() {
|
||||
@@ -102,13 +101,13 @@ export const DateRangeFilter = forwardRef(
|
||||
return null;
|
||||
}
|
||||
|
||||
return { value: valueRef.current };
|
||||
return { value };
|
||||
},
|
||||
|
||||
setModel(model?: { value: Schema.DateRange } | null) {
|
||||
valueRef.current =
|
||||
model?.value || props?.defaultValue || defaultValue;
|
||||
setValue(valueRef.current);
|
||||
setValue(
|
||||
model?.value || props?.defaultRangeFilter || defaultFilterValue
|
||||
);
|
||||
},
|
||||
};
|
||||
});
|
||||
@@ -186,8 +185,10 @@ export const DateRangeFilter = forwardRef(
|
||||
update = { ...update, end: checkForEndDate(endDate, startDate) };
|
||||
|
||||
if (validate(name, date, update)) {
|
||||
valueRef.current = { ...valueRef.current, ...update };
|
||||
setValue(valueRef.current);
|
||||
setValue((curr) => ({
|
||||
...curr,
|
||||
...update,
|
||||
}));
|
||||
}
|
||||
};
|
||||
useEffect(() => {
|
||||
@@ -240,8 +241,7 @@ export const DateRangeFilter = forwardRef(
|
||||
className="ag-standard-button ag-filter-apply-panel-button"
|
||||
onClick={() => {
|
||||
setError('');
|
||||
valueRef.current = defaultDates;
|
||||
setValue(valueRef.current);
|
||||
setValue(defaultDates);
|
||||
}}
|
||||
>
|
||||
{t('Reset')}
|
||||
|
||||
@@ -1,17 +1,10 @@
|
||||
import type { ChangeEvent } from 'react';
|
||||
import {
|
||||
forwardRef,
|
||||
useEffect,
|
||||
useImperativeHandle,
|
||||
useState,
|
||||
useRef,
|
||||
} from 'react';
|
||||
import { forwardRef, useEffect, useImperativeHandle, useState } from 'react';
|
||||
import type { IDoesFilterPassParams, IFilterParams } from 'ag-grid-community';
|
||||
import { t } from '@vegaprotocol/i18n';
|
||||
|
||||
export const SetFilter = forwardRef((props: IFilterParams, ref) => {
|
||||
const [value, setValue] = useState<string[]>([]);
|
||||
const valueRef = useRef(value);
|
||||
|
||||
// expose AG Grid Filter Lifecycle callbacks
|
||||
useImperativeHandle(ref, () => {
|
||||
@@ -35,28 +28,29 @@ export const SetFilter = forwardRef((props: IFilterParams, ref) => {
|
||||
},
|
||||
|
||||
isFilterActive() {
|
||||
return valueRef.current.length !== 0;
|
||||
return value.length !== 0;
|
||||
},
|
||||
|
||||
getModel() {
|
||||
if (!this.isFilterActive()) {
|
||||
return null;
|
||||
}
|
||||
return { value: valueRef.current };
|
||||
|
||||
return { value };
|
||||
},
|
||||
|
||||
setModel(model?: { value: string[] } | null) {
|
||||
valueRef.current = !model ? [] : model.value;
|
||||
setValue(valueRef.current);
|
||||
setValue(!model ? [] : model.value);
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
const onChange = (event: ChangeEvent<HTMLInputElement>) => {
|
||||
valueRef.current = event.target.checked
|
||||
? [...value, event.target.value]
|
||||
: value.filter((v) => v !== event.target.value);
|
||||
setValue(valueRef.current);
|
||||
setValue(
|
||||
event.target.checked
|
||||
? [...value, event.target.value]
|
||||
: value.filter((v) => v !== event.target.value)
|
||||
);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
@@ -83,7 +77,7 @@ export const SetFilter = forwardRef((props: IFilterParams, ref) => {
|
||||
<button
|
||||
type="button"
|
||||
className="ag-standard-button ag-filter-apply-panel-button"
|
||||
onClick={() => setValue((valueRef.current = []))}
|
||||
onClick={() => setValue([])}
|
||||
>
|
||||
{t('Reset')}
|
||||
</button>
|
||||
|
||||
@@ -15,8 +15,8 @@ export const useInitialMargin = (
|
||||
marketId: OrderSubmissionBody['orderSubmission']['marketId'],
|
||||
order?: OrderSubmissionBody['orderSubmission']
|
||||
) => {
|
||||
const { pubKey } = useVegaWallet();
|
||||
const commonVariables = { marketId, partyId: pubKey || '' };
|
||||
const { pubKey: partyId } = useVegaWallet();
|
||||
const commonVariables = { marketId, partyId: partyId || '' };
|
||||
const { data: marketData } = useDataProvider({
|
||||
dataProvider: marketDataProvider,
|
||||
variables: { marketId },
|
||||
@@ -24,7 +24,7 @@ export const useInitialMargin = (
|
||||
const { data: activeVolumeAndMargin } = useDataProvider({
|
||||
dataProvider: volumeAndMarginProvider,
|
||||
variables: commonVariables,
|
||||
skip: !pubKey,
|
||||
skip: !partyId,
|
||||
});
|
||||
const { data: marketInfo } = useDataProvider({
|
||||
dataProvider: marketInfoProvider,
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
export * from './use-environment';
|
||||
export * from './use-links';
|
||||
export * from './use-node-health';
|
||||
export * from './use-vega-releases';
|
||||
export * from './use-vega-release';
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,41 @@
|
||||
import { renderHook, waitFor } from '@testing-library/react';
|
||||
import fetchMock from 'fetch-mock';
|
||||
import {
|
||||
GITHUB_VEGA_DEV_RELEASES,
|
||||
GITHUB_VEGA_RELEASES,
|
||||
} from './use-vega-releases';
|
||||
import {
|
||||
GITHUB_VEGA_RELEASES_DATA,
|
||||
GITHUB_VEGA_DEV_RELEASES_DATA,
|
||||
} from './mocks/github-releases';
|
||||
import { useVegaRelease } from './use-vega-release';
|
||||
|
||||
describe('useVegaRelease', () => {
|
||||
beforeEach(() => {
|
||||
fetchMock.get(GITHUB_VEGA_RELEASES, GITHUB_VEGA_RELEASES_DATA);
|
||||
fetchMock.get(GITHUB_VEGA_DEV_RELEASES, GITHUB_VEGA_DEV_RELEASES_DATA);
|
||||
});
|
||||
afterEach(() => {
|
||||
fetchMock.reset();
|
||||
});
|
||||
|
||||
it('should return release information by given tag', async () => {
|
||||
const { result } = renderHook(() => useVegaRelease('v0.70.1'));
|
||||
await waitFor(() => {
|
||||
expect(result.current).toBeTruthy();
|
||||
expect(result.current?.tagName).toEqual('v0.70.1');
|
||||
expect(result.current?.htmlUrl).toEqual(
|
||||
'https://github.com/vegaprotocol/vega/releases/tag/v0.70.1'
|
||||
);
|
||||
expect(result.current?.name).toEqual('v0.70.1');
|
||||
expect(result.current?.isDraft).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
it('should return undefined when a release cannot be found', async () => {
|
||||
const { result } = renderHook(() => useVegaRelease('v0.70.1'));
|
||||
await waitFor(() => {
|
||||
expect(result.current).toEqual(undefined);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,9 @@
|
||||
import { useMemo } from 'react';
|
||||
import { useVegaReleases } from './use-vega-releases';
|
||||
|
||||
export const useVegaRelease = (tag: string, includeDevReleases = false) => {
|
||||
const { data } = useVegaReleases();
|
||||
return useMemo(() => {
|
||||
return data?.find((r) => r.tagName === tag);
|
||||
}, [data, tag]);
|
||||
};
|
||||
@@ -0,0 +1,58 @@
|
||||
import { renderHook, waitFor } from '@testing-library/react';
|
||||
import fetchMock from 'fetch-mock';
|
||||
import {
|
||||
GITHUB_VEGA_DEV_RELEASES,
|
||||
GITHUB_VEGA_RELEASES,
|
||||
useVegaReleases,
|
||||
} from './use-vega-releases';
|
||||
import {
|
||||
GITHUB_VEGA_RELEASES_DATA,
|
||||
GITHUB_VEGA_DEV_RELEASES_DATA,
|
||||
} from './mocks/github-releases';
|
||||
|
||||
describe('useVegaReleases', () => {
|
||||
afterEach(() => {
|
||||
fetchMock.reset();
|
||||
});
|
||||
|
||||
it('should return an empty list when request is unsuccessful', async () => {
|
||||
fetchMock.get(GITHUB_VEGA_RELEASES, 404);
|
||||
fetchMock.get(GITHUB_VEGA_DEV_RELEASES, 404);
|
||||
|
||||
const { result } = renderHook(() => useVegaReleases());
|
||||
expect(result.current.loading).toBeTruthy();
|
||||
await waitFor(() => {
|
||||
expect(result.current.loading).toBeFalsy();
|
||||
expect(result.current.data).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
it('should return a list of releases', async () => {
|
||||
fetchMock.get(GITHUB_VEGA_RELEASES, GITHUB_VEGA_RELEASES_DATA);
|
||||
fetchMock.get(GITHUB_VEGA_DEV_RELEASES, GITHUB_VEGA_DEV_RELEASES_DATA);
|
||||
|
||||
const { result } = renderHook(() => useVegaReleases());
|
||||
expect(result.current.loading).toBeTruthy();
|
||||
await waitFor(() => {
|
||||
expect(result.current.loading).toBeFalsy();
|
||||
expect(result.current).not.toEqual([]);
|
||||
const data = result.current.data;
|
||||
expect(data?.[0].tagName).toEqual('v0.70.3');
|
||||
expect(data?.[0].htmlUrl).toEqual(
|
||||
'https://github.com/vegaprotocol/vega/releases/tag/v0.70.3'
|
||||
);
|
||||
expect(data?.[1].tagName).toEqual('v0.70.2');
|
||||
expect(data?.[2].tagName).toEqual('v0.70.1');
|
||||
});
|
||||
});
|
||||
|
||||
it('should return a list of releases including dev releases', async () => {
|
||||
fetchMock.get(GITHUB_VEGA_RELEASES, GITHUB_VEGA_RELEASES_DATA);
|
||||
fetchMock.get(GITHUB_VEGA_DEV_RELEASES, GITHUB_VEGA_DEV_RELEASES_DATA);
|
||||
const { result } = renderHook(() => useVegaReleases(true));
|
||||
await waitFor(() => {
|
||||
expect(result.current.data?.length).toBeGreaterThan(30);
|
||||
expect(fetchMock.calls().length).toEqual(2);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,124 @@
|
||||
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import z from 'zod';
|
||||
|
||||
export const GITHUB_VEGA_RELEASES =
|
||||
'https://api.github.com/repos/vegaprotocol/vega/releases';
|
||||
export const GITHUB_VEGA_DEV_RELEASES =
|
||||
'https://api.github.com/repos/vegaprotocol/vega-dev-releases/releases';
|
||||
|
||||
const GithubReleaseSchema = z.object({
|
||||
url: z.string(),
|
||||
html_url: z.string(),
|
||||
id: z.number(),
|
||||
tag_name: z.string(),
|
||||
name: z.string().nullable(),
|
||||
draft: z.boolean(),
|
||||
created_at: z.string().datetime(),
|
||||
});
|
||||
|
||||
const GithubReleasesSchema = z.array(GithubReleaseSchema);
|
||||
|
||||
type ReleaseInfo = {
|
||||
id: number;
|
||||
name: string;
|
||||
tagName: string;
|
||||
htmlUrl: string;
|
||||
url: string;
|
||||
isDraft: boolean;
|
||||
createdAt: Date;
|
||||
isDevRelease: boolean;
|
||||
};
|
||||
|
||||
const toReleaseInfo = (
|
||||
releaseData: z.infer<typeof GithubReleaseSchema>,
|
||||
isDevRelease: boolean
|
||||
): ReleaseInfo => ({
|
||||
id: releaseData.id,
|
||||
name: releaseData.name || '',
|
||||
tagName: releaseData.tag_name,
|
||||
htmlUrl: releaseData.html_url,
|
||||
url: releaseData.url,
|
||||
isDraft: releaseData.draft,
|
||||
createdAt: new Date(releaseData.created_at),
|
||||
isDevRelease,
|
||||
});
|
||||
|
||||
enum ReleaseFeed {
|
||||
// @ts-ignore TS18033 - allowed in 5.0
|
||||
Vega = GITHUB_VEGA_RELEASES,
|
||||
// @ts-ignore TS18033
|
||||
VegaDev = GITHUB_VEGA_DEV_RELEASES,
|
||||
}
|
||||
|
||||
const fetchReleases = async (feed: ReleaseFeed) => {
|
||||
const response = await fetch(String(feed), {
|
||||
cache: 'force-cache',
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
const json = await response.json();
|
||||
const data = GithubReleasesSchema.parse(json);
|
||||
return data.map((d) => toReleaseInfo(d, feed === ReleaseFeed.VegaDev));
|
||||
}
|
||||
|
||||
return [];
|
||||
};
|
||||
|
||||
type State = {
|
||||
loading: boolean;
|
||||
data: ReleaseInfo[] | null;
|
||||
error: Error | null | undefined;
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieves a list of vega releases from github.
|
||||
* First element is the newest.
|
||||
*/
|
||||
export const useVegaReleases = (includeDevReleases = false) => {
|
||||
const [state, setState] = useState<State>({
|
||||
loading: true,
|
||||
data: null,
|
||||
error: null,
|
||||
});
|
||||
|
||||
const fetchData = useCallback(() => {
|
||||
let mounted = true;
|
||||
|
||||
Promise.all(
|
||||
includeDevReleases
|
||||
? [fetchReleases(ReleaseFeed.Vega), fetchReleases(ReleaseFeed.VegaDev)]
|
||||
: [fetchReleases(ReleaseFeed.Vega)]
|
||||
)
|
||||
.then(([vega, vegaDev]) => {
|
||||
if (mounted) {
|
||||
setState({
|
||||
loading: false,
|
||||
data: (vegaDev ? vega.concat(vegaDev) : vega).sort(
|
||||
(a, b) => b.createdAt.valueOf() - a.createdAt.valueOf()
|
||||
),
|
||||
error: null,
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
if (mounted) {
|
||||
setState({
|
||||
loading: false,
|
||||
data: null,
|
||||
error: err,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return () => {
|
||||
mounted = false;
|
||||
};
|
||||
}, [includeDevReleases, setState]);
|
||||
|
||||
useEffect(() => {
|
||||
fetchData();
|
||||
}, [fetchData]);
|
||||
|
||||
return state;
|
||||
};
|
||||
@@ -38,10 +38,10 @@ export const TransferTooltipCellComponent = ({
|
||||
);
|
||||
};
|
||||
|
||||
const defaultValue = { start: formatRFC3339(subDays(Date.now(), 7)) };
|
||||
const defaultRangeFilter = { start: formatRFC3339(subDays(Date.now(), 7)) };
|
||||
const dateRangeFilterParams = {
|
||||
maxNextDays: 0,
|
||||
defaultValue,
|
||||
defaultRangeFilter,
|
||||
};
|
||||
type LedgerEntryProps = TypedDataAgGrid<LedgerEntry>;
|
||||
|
||||
|
||||
@@ -20,7 +20,6 @@ import type {
|
||||
OrdersQueryVariables,
|
||||
} from './__generated__/Orders';
|
||||
import { OrdersDocument, OrdersUpdateDocument } from './__generated__/Orders';
|
||||
import type { ApolloClient } from '@apollo/client';
|
||||
|
||||
export type Order = Omit<OrderFieldsFragment, 'market'> & {
|
||||
market?: Market;
|
||||
@@ -82,31 +81,8 @@ const getData = (
|
||||
): Edge<OrderFieldsFragment>[] =>
|
||||
responseData?.party?.ordersConnection?.edges || [];
|
||||
|
||||
const getDelta = (
|
||||
subscriptionData: OrdersUpdateSubscription,
|
||||
variables: OrdersQueryVariables,
|
||||
client: ApolloClient<object>
|
||||
) => {
|
||||
if (!subscriptionData.orders) {
|
||||
return [];
|
||||
}
|
||||
subscriptionData.orders.forEach((order) => {
|
||||
client.cache.modify({
|
||||
id: client.cache.identify({
|
||||
__typename: 'Order',
|
||||
id: order.id,
|
||||
}),
|
||||
fields: {
|
||||
price: () => order.price,
|
||||
size: () => order.size,
|
||||
remaining: () => order.remaining,
|
||||
updatedAt: () => order.updatedAt,
|
||||
status: () => order.status,
|
||||
},
|
||||
});
|
||||
});
|
||||
return subscriptionData.orders;
|
||||
};
|
||||
const getDelta = (subscriptionData: OrdersUpdateSubscription) =>
|
||||
subscriptionData.orders || [];
|
||||
|
||||
const getPageInfo = (responseData: OrdersQuery): PageInfo | null =>
|
||||
responseData.party?.ordersConnection?.pageInfo || null;
|
||||
@@ -174,7 +150,7 @@ export const update = (
|
||||
});
|
||||
};
|
||||
|
||||
const ordersProvider = makeDataProvider<
|
||||
export const ordersProvider = makeDataProvider<
|
||||
OrdersQuery,
|
||||
ReturnType<typeof getData>,
|
||||
OrdersUpdateSubscription,
|
||||
@@ -189,36 +165,11 @@ const ordersProvider = makeDataProvider<
|
||||
pagination: {
|
||||
getPageInfo,
|
||||
append,
|
||||
first: 1000,
|
||||
first: 100,
|
||||
},
|
||||
additionalContext: { isEnlargedTimeout: true },
|
||||
});
|
||||
|
||||
export const activeOrdersProvider = makeDerivedDataProvider<
|
||||
ReturnType<typeof getData>,
|
||||
never,
|
||||
{ partyId: string; marketId?: string }
|
||||
>(
|
||||
[
|
||||
(callback, client, variables) =>
|
||||
ordersProvider(callback, client, {
|
||||
partyId: variables.partyId,
|
||||
filter: {
|
||||
status: [OrderStatus.STATUS_ACTIVE, OrderStatus.STATUS_PARKED],
|
||||
},
|
||||
}),
|
||||
],
|
||||
(partsData, variables, prevData, parts, subscriptions) => {
|
||||
if (!parts[0].isUpdate && subscriptions && subscriptions[0].load) {
|
||||
subscriptions[0].load();
|
||||
}
|
||||
const orders = partsData[0] as ReturnType<typeof getData>;
|
||||
return variables.marketId
|
||||
? orders.filter((edge) => variables.marketId === edge.node.market.id)
|
||||
: orders;
|
||||
}
|
||||
);
|
||||
|
||||
export const ordersWithMarketProvider = makeDerivedDataProvider<
|
||||
(OrderEdge | null)[],
|
||||
Order[],
|
||||
@@ -242,20 +193,63 @@ export const ordersWithMarketProvider = makeDerivedDataProvider<
|
||||
combineInsertionData<Order>
|
||||
);
|
||||
|
||||
const hasActiveOrderProviderInternal = makeDataProvider<
|
||||
OrdersQuery,
|
||||
boolean,
|
||||
OrdersUpdateSubscription,
|
||||
ReturnType<typeof getDelta>,
|
||||
OrdersQueryVariables
|
||||
>({
|
||||
query: OrdersDocument,
|
||||
subscriptionQuery: OrdersUpdateDocument,
|
||||
update: (
|
||||
data: boolean | null,
|
||||
delta: ReturnType<typeof getDelta>,
|
||||
reload: () => void
|
||||
) => {
|
||||
const orders = delta?.filter(
|
||||
(order) => !(order.peggedOrder || order.liquidityProvisionId)
|
||||
);
|
||||
if (!orders?.length) {
|
||||
return data;
|
||||
}
|
||||
const hasActiveOrders = orders.some(
|
||||
(order) => order.status === OrderStatus.STATUS_ACTIVE
|
||||
);
|
||||
if (hasActiveOrders) {
|
||||
return true;
|
||||
} else if (data && !hasActiveOrders) {
|
||||
reload();
|
||||
}
|
||||
return data;
|
||||
},
|
||||
getData: (responseData: OrdersQuery | null) => {
|
||||
const hasActiveOrder = !!responseData?.party?.ordersConnection?.edges?.some(
|
||||
(order) => !(order.node.peggedOrder || order.node.liquidityProvision)
|
||||
);
|
||||
return hasActiveOrder;
|
||||
},
|
||||
getDelta,
|
||||
});
|
||||
|
||||
export const hasActiveOrderProvider = makeDerivedDataProvider<
|
||||
boolean,
|
||||
never,
|
||||
{ partyId: string; marketId?: string }
|
||||
>([activeOrdersProvider], (parts) => !!parts[0].length);
|
||||
|
||||
export const hasAmendableOrderProvider = makeDerivedDataProvider<
|
||||
boolean,
|
||||
never,
|
||||
{ partyId: string; marketId?: string }
|
||||
>([activeOrdersProvider], (parts) => {
|
||||
const activeOrders = parts[0] as ReturnType<typeof getData>;
|
||||
const hasAmendableOrder = activeOrders.some(
|
||||
(edge) => !(edge.node.liquidityProvision || edge.node.peggedOrder)
|
||||
);
|
||||
return hasAmendableOrder;
|
||||
});
|
||||
>(
|
||||
[
|
||||
(callback, client, { partyId, marketId }) =>
|
||||
hasActiveOrderProviderInternal(callback, client, {
|
||||
marketIds: marketId ? [marketId] : undefined,
|
||||
filter: {
|
||||
status: [OrderStatus.STATUS_ACTIVE],
|
||||
excludeLiquidity: true,
|
||||
},
|
||||
pagination: {
|
||||
first: 1,
|
||||
},
|
||||
partyId,
|
||||
} as OrdersQueryVariables),
|
||||
],
|
||||
(parts) => parts[0]
|
||||
);
|
||||
|
||||
@@ -6,12 +6,10 @@ import { OrderListManager } from './order-list-manager';
|
||||
export const OrderListContainer = ({
|
||||
marketId,
|
||||
onMarketClick,
|
||||
onOrderTypeClick,
|
||||
enforceBottomPlaceholder,
|
||||
}: {
|
||||
marketId?: string;
|
||||
onMarketClick?: (marketId: string, metaKey?: boolean) => void;
|
||||
onOrderTypeClick?: (marketId: string, metaKey?: boolean) => void;
|
||||
enforceBottomPlaceholder?: boolean;
|
||||
}) => {
|
||||
const { pubKey, isReadOnly } = useVegaWallet();
|
||||
@@ -25,7 +23,6 @@ export const OrderListContainer = ({
|
||||
partyId={pubKey}
|
||||
marketId={marketId}
|
||||
onMarketClick={onMarketClick}
|
||||
onOrderTypeClick={onOrderTypeClick}
|
||||
isReadOnly={isReadOnly}
|
||||
enforceBottomPlaceholder={enforceBottomPlaceholder}
|
||||
/>
|
||||
|
||||
@@ -8,7 +8,7 @@ import type { GridReadyEvent } from 'ag-grid-community';
|
||||
|
||||
import { OrderListTable } from '../order-list/order-list';
|
||||
import { useOrderListData } from './use-order-list-data';
|
||||
import { useHasAmendableOrder } from '../../order-hooks/use-has-amendable-order';
|
||||
import { useHasActiveOrder } from '../../order-hooks/use-has-active-order';
|
||||
import type { Filter, Sort } from './use-order-list-data';
|
||||
import { useBottomPlaceholder } from '@vegaprotocol/react-helpers';
|
||||
import { OrderStatus } from '@vegaprotocol/types';
|
||||
@@ -16,7 +16,6 @@ import {
|
||||
normalizeOrderAmendment,
|
||||
useVegaTransactionStore,
|
||||
} from '@vegaprotocol/wallet';
|
||||
import isEqual from 'lodash/isEqual';
|
||||
import type { OrderTxUpdateFieldsFragment } from '@vegaprotocol/wallet';
|
||||
import { OrderEditDialog } from '../order-list/order-edit-dialog';
|
||||
import type { Order, OrderEdge } from '../order-data-provider';
|
||||
@@ -25,23 +24,31 @@ export interface OrderListManagerProps {
|
||||
partyId: string;
|
||||
marketId?: string;
|
||||
onMarketClick?: (marketId: string, metaKey?: boolean) => void;
|
||||
onOrderTypeClick?: (marketId: string, metaKey?: boolean) => void;
|
||||
isReadOnly: boolean;
|
||||
enforceBottomPlaceholder?: boolean;
|
||||
}
|
||||
|
||||
const CancelAllOrdersButton = ({ onClick }: { onClick: () => void }) => (
|
||||
<div className="dark:bg-black/75 bg-white/75 h-auto flex justify-end px-[11px] py-2 absolute bottom-0 right-3 rounded">
|
||||
<Button
|
||||
variant="primary"
|
||||
size="sm"
|
||||
onClick={onClick}
|
||||
data-testid="cancelAll"
|
||||
>
|
||||
{t('Cancel all')}
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
const CancelAllOrdersButton = ({
|
||||
onClick,
|
||||
marketId,
|
||||
}: {
|
||||
onClick: (marketId?: string) => void;
|
||||
marketId?: string;
|
||||
}) => {
|
||||
const hasActiveOrder = useHasActiveOrder(marketId);
|
||||
return hasActiveOrder ? (
|
||||
<div className="dark:bg-black/75 bg-white/75 h-auto flex justify-end px-[11px] py-2 absolute bottom-0 right-3 rounded">
|
||||
<Button
|
||||
variant="primary"
|
||||
size="sm"
|
||||
onClick={() => onClick(marketId)}
|
||||
data-testid="cancelAll"
|
||||
>
|
||||
{t('Cancel all')}
|
||||
</Button>
|
||||
</div>
|
||||
) : null;
|
||||
};
|
||||
|
||||
const initialFilter: Filter = {
|
||||
status: {
|
||||
@@ -53,7 +60,6 @@ export const OrderListManager = ({
|
||||
partyId,
|
||||
marketId,
|
||||
onMarketClick,
|
||||
onOrderTypeClick,
|
||||
isReadOnly,
|
||||
enforceBottomPlaceholder,
|
||||
}: OrderListManagerProps) => {
|
||||
@@ -62,10 +68,9 @@ export const OrderListManager = ({
|
||||
const scrolledToTop = useRef(false);
|
||||
const [sort, setSort] = useState<Sort[] | undefined>();
|
||||
const [filter, setFilter] = useState<Filter | undefined>(initialFilter);
|
||||
const filterRef = useRef(initialFilter);
|
||||
const [editOrder, setEditOrder] = useState<Order | null>(null);
|
||||
const create = useVegaTransactionStore((state) => state.create);
|
||||
const hasAmendableOrder = useHasAmendableOrder(marketId);
|
||||
const hasActiveOrder = useHasActiveOrder(marketId);
|
||||
|
||||
const { data, error, loading, reload } = useOrderListData({
|
||||
partyId,
|
||||
@@ -81,16 +86,12 @@ export const OrderListManager = ({
|
||||
...bottomPlaceholderProps
|
||||
} = useBottomPlaceholder<Order>({
|
||||
gridRef,
|
||||
disabled: !enforceBottomPlaceholder && !isReadOnly && !hasAmendableOrder,
|
||||
disabled: !enforceBottomPlaceholder && !isReadOnly && !hasActiveOrder,
|
||||
});
|
||||
|
||||
const onFilterChanged = useCallback(
|
||||
(event: FilterChangedEvent) => {
|
||||
const updatedFilter = event.api.getFilterModel();
|
||||
if (isEqual(updatedFilter, filterRef.current)) {
|
||||
return;
|
||||
}
|
||||
filterRef.current = updatedFilter;
|
||||
if (Object.keys(updatedFilter).length) {
|
||||
setFilter(updatedFilter);
|
||||
} else {
|
||||
@@ -141,13 +142,16 @@ export const OrderListManager = ({
|
||||
setDataCount(gridRef.current?.api?.getModel().getRowCount() ?? 0);
|
||||
}, [data]);
|
||||
|
||||
const cancelAll = useCallback(() => {
|
||||
create({
|
||||
orderCancellation: {
|
||||
marketId,
|
||||
},
|
||||
});
|
||||
}, [create, marketId]);
|
||||
const cancelAll = useCallback(
|
||||
(marketId?: string) => {
|
||||
create({
|
||||
orderCancellation: {
|
||||
marketId,
|
||||
},
|
||||
});
|
||||
},
|
||||
[create]
|
||||
);
|
||||
const extractedData =
|
||||
data && !loading
|
||||
? data
|
||||
@@ -167,7 +171,6 @@ export const OrderListManager = ({
|
||||
cancel={cancel}
|
||||
setEditOrder={setEditOrder}
|
||||
onMarketClick={onMarketClick}
|
||||
onOrderTypeClick={onOrderTypeClick}
|
||||
isReadOnly={isReadOnly}
|
||||
blockLoadDebounceMillis={100}
|
||||
suppressLoadingOverlay
|
||||
@@ -185,8 +188,8 @@ export const OrderListManager = ({
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{!isReadOnly && hasAmendableOrder && (
|
||||
<CancelAllOrdersButton onClick={cancelAll} />
|
||||
{!isReadOnly && (
|
||||
<CancelAllOrdersButton onClick={cancelAll} marketId={marketId} />
|
||||
)}
|
||||
{editOrder && (
|
||||
<OrderEditDialog
|
||||
|
||||
@@ -71,27 +71,17 @@ export const useOrderListData = ({
|
||||
// define variable as const to get type safety, using generic with useMemo resulted in lost type safety
|
||||
const allVars: OrdersQueryVariables & OrdersUpdateSubscriptionVariables = {
|
||||
partyId,
|
||||
filter: {
|
||||
dateRange: filter?.updatedAt?.value,
|
||||
status: filter?.status?.value,
|
||||
timeInForce: filter?.timeInForce?.value,
|
||||
types: filter?.type?.value,
|
||||
},
|
||||
pagination: {
|
||||
first: 1000,
|
||||
},
|
||||
};
|
||||
if (
|
||||
filter?.updatedAt?.value ||
|
||||
filter?.status?.value.length ||
|
||||
filter?.timeInForce?.value.length ||
|
||||
filter?.type?.value.length
|
||||
) {
|
||||
allVars.filter = {};
|
||||
if (filter?.updatedAt?.value) {
|
||||
allVars.filter.dateRange = filter?.updatedAt?.value;
|
||||
}
|
||||
if (filter?.status?.value.length) {
|
||||
allVars.filter.status = filter?.status?.value;
|
||||
}
|
||||
if (filter?.timeInForce?.value.length) {
|
||||
allVars.filter.timeInForce = filter?.timeInForce?.value;
|
||||
}
|
||||
if (filter?.type?.value.length) {
|
||||
allVars.filter.types = filter?.type?.value;
|
||||
}
|
||||
}
|
||||
|
||||
return allVars;
|
||||
}, [partyId, filter]);
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@ import {
|
||||
negativeClassNames,
|
||||
positiveClassNames,
|
||||
MarketNameCell,
|
||||
OrderTypeCell,
|
||||
} from '@vegaprotocol/datagrid';
|
||||
import type {
|
||||
TypedDataAgGrid,
|
||||
@@ -32,16 +31,12 @@ export type OrderListTableProps = OrderListProps & {
|
||||
cancel: (order: Order) => void;
|
||||
setEditOrder: (order: Order) => void;
|
||||
onMarketClick?: (marketId: string, metaKey?: boolean) => void;
|
||||
onOrderTypeClick?: (marketId: string, metaKey?: boolean) => void;
|
||||
isReadOnly: boolean;
|
||||
};
|
||||
|
||||
export const OrderListTable = memo(
|
||||
forwardRef<AgGridReact, OrderListTableProps>(
|
||||
(
|
||||
{ cancel, setEditOrder, onMarketClick, onOrderTypeClick, ...props },
|
||||
ref
|
||||
) => {
|
||||
({ cancel, setEditOrder, onMarketClick, ...props }, ref) => {
|
||||
return (
|
||||
<AgGrid
|
||||
ref={ref}
|
||||
@@ -56,7 +51,7 @@ export const OrderListTable = memo(
|
||||
height: '100%',
|
||||
}}
|
||||
getRowId={({ data }) => data.id}
|
||||
components={{ MarketNameCell, OrderTypeCell }}
|
||||
components={{ MarketNameCell }}
|
||||
{...props}
|
||||
>
|
||||
<AgGridColumn
|
||||
@@ -108,9 +103,17 @@ export const OrderListTable = memo(
|
||||
filterParams={{
|
||||
set: Schema.OrderTypeMapping,
|
||||
}}
|
||||
cellRenderer="OrderTypeCell"
|
||||
cellRendererParams={{
|
||||
onClick: onOrderTypeClick,
|
||||
valueFormatter={({
|
||||
data: order,
|
||||
value,
|
||||
}: VegaValueFormatterParams<Order, 'type'>) => {
|
||||
if (!order) {
|
||||
return undefined;
|
||||
}
|
||||
if (!value) return '-';
|
||||
if (order?.peggedOrder) return t('Pegged');
|
||||
if (order?.liquidityProvision) return t('Liquidity provision');
|
||||
return Schema.OrderTypeMapping[value];
|
||||
}}
|
||||
minWidth={80}
|
||||
/>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
export * from './__generated__/OrdersSubscription';
|
||||
export * from './use-has-amendable-order';
|
||||
export * from './use-has-active-order';
|
||||
export * from './use-order-update';
|
||||
export * from './use-pending-orders-volume';
|
||||
export * from './use-order-store';
|
||||
|
||||
+6
-6
@@ -1,17 +1,17 @@
|
||||
import { useCallback, useState } from 'react';
|
||||
import { hasAmendableOrderProvider } from '../components/order-data-provider';
|
||||
import { hasActiveOrderProvider } from '../components/order-data-provider/';
|
||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||
import { useDataProvider } from '@vegaprotocol/react-helpers';
|
||||
|
||||
export const useHasAmendableOrder = (marketId?: string) => {
|
||||
export const useHasActiveOrder = (marketId?: string) => {
|
||||
const { pubKey } = useVegaWallet();
|
||||
const [hasAmendableOrder, setHasAmendableOrder] = useState(false);
|
||||
const [hasActiveOrder, setHasActiveOrder] = useState(false);
|
||||
const update = useCallback(({ data }: { data: boolean | null }) => {
|
||||
setHasAmendableOrder(Boolean(data));
|
||||
setHasActiveOrder(Boolean(data));
|
||||
return true;
|
||||
}, []);
|
||||
useDataProvider({
|
||||
dataProvider: hasAmendableOrderProvider,
|
||||
dataProvider: hasActiveOrderProvider,
|
||||
update,
|
||||
variables: {
|
||||
partyId: pubKey || '',
|
||||
@@ -20,5 +20,5 @@ export const useHasAmendableOrder = (marketId?: string) => {
|
||||
skip: !pubKey,
|
||||
});
|
||||
|
||||
return hasAmendableOrder;
|
||||
return hasActiveOrder;
|
||||
};
|
||||
@@ -0,0 +1,74 @@
|
||||
import { useState, useCallback } from 'react';
|
||||
import { OrderStatus, Side } from '@vegaprotocol/types';
|
||||
import { ordersProvider } from '../components/order-data-provider/order-data-provider';
|
||||
import type { OrderFieldsFragment } from '../components/order-data-provider/__generated__/Orders';
|
||||
import type { Edge } from '@vegaprotocol/utils';
|
||||
import { useDataProvider } from '@vegaprotocol/react-helpers';
|
||||
|
||||
const sumVolume = (orders: (Edge<OrderFieldsFragment> | null)[], side: Side) =>
|
||||
orders
|
||||
.reduce(
|
||||
(sum, order) =>
|
||||
order?.node.side === side
|
||||
? sum +
|
||||
BigInt(
|
||||
order?.node.status === OrderStatus.STATUS_PARTIALLY_FILLED
|
||||
? order?.node.remaining
|
||||
: order?.node.size
|
||||
)
|
||||
: sum,
|
||||
BigInt(0)
|
||||
)
|
||||
.toString();
|
||||
|
||||
export const useActiveOrdersVolumeAndMargin = (
|
||||
partyId: string | null | undefined,
|
||||
marketId: string
|
||||
) => {
|
||||
const [buyVolume, setBuyVolume] = useState<string | undefined>();
|
||||
const [sellVolume, setSellVolume] = useState<string | undefined>();
|
||||
const [buyInitialMargin, setBuyInitialMargin] = useState<
|
||||
string | undefined
|
||||
>();
|
||||
const [sellInitialMargin, setSellInitialMargin] = useState<
|
||||
string | undefined
|
||||
>();
|
||||
const update = useCallback(
|
||||
({ data }: { data: (Edge<OrderFieldsFragment> | null)[] | null }) => {
|
||||
if (!data) {
|
||||
setBuyVolume(undefined);
|
||||
setSellVolume(undefined);
|
||||
setBuyInitialMargin(undefined);
|
||||
setSellInitialMargin(undefined);
|
||||
} else {
|
||||
setBuyVolume(sumVolume(data, Side.SIDE_BUY));
|
||||
setSellVolume(sumVolume(data, Side.SIDE_SELL));
|
||||
}
|
||||
return true;
|
||||
},
|
||||
[]
|
||||
);
|
||||
useDataProvider({
|
||||
dataProvider: ordersProvider,
|
||||
update,
|
||||
variables: {
|
||||
partyId: partyId || '',
|
||||
marketIds: [marketId],
|
||||
filter: {
|
||||
status: [
|
||||
OrderStatus.STATUS_ACTIVE,
|
||||
OrderStatus.STATUS_PARTIALLY_FILLED,
|
||||
],
|
||||
},
|
||||
},
|
||||
skip: !partyId,
|
||||
});
|
||||
return buyVolume || sellVolume
|
||||
? {
|
||||
buyVolume,
|
||||
sellVolume,
|
||||
buyInitialMargin,
|
||||
sellInitialMargin,
|
||||
}
|
||||
: undefined;
|
||||
};
|
||||
@@ -30,12 +30,12 @@ import {
|
||||
import { marginsDataProvider } from './margin-data-provider';
|
||||
import { calculateMargins } from './margin-calculator';
|
||||
import type { Edge } from '@vegaprotocol/utils';
|
||||
import { Side } from '@vegaprotocol/types';
|
||||
import { OrderStatus, Side } from '@vegaprotocol/types';
|
||||
import { marketInfoProvider } from '@vegaprotocol/market-info';
|
||||
import type { MarketInfoQuery } from '@vegaprotocol/market-info';
|
||||
import { marketDataProvider } from '@vegaprotocol/market-list';
|
||||
import type { MarketData } from '@vegaprotocol/market-list';
|
||||
import { activeOrdersProvider } from '@vegaprotocol/orders';
|
||||
import { ordersProvider } from '@vegaprotocol/orders';
|
||||
import type { OrderFieldsFragment } from '@vegaprotocol/orders';
|
||||
import type { PositionStatus } from '@vegaprotocol/types';
|
||||
|
||||
@@ -350,9 +350,12 @@ export const volumeAndMarginProvider = makeDerivedDataProvider<
|
||||
>(
|
||||
[
|
||||
(callback, client, { partyId, marketId }) =>
|
||||
activeOrdersProvider(callback, client, {
|
||||
ordersProvider(callback, client, {
|
||||
partyId,
|
||||
marketId,
|
||||
marketIds: [marketId],
|
||||
filter: {
|
||||
status: [OrderStatus.STATUS_ACTIVE, OrderStatus.STATUS_PARKED],
|
||||
},
|
||||
}),
|
||||
(callback, client, variables) =>
|
||||
marketDataProvider(callback, client, { marketId: variables.marketId }),
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { useState, useEffect, useRef, useMemo, useCallback } from 'react';
|
||||
import { useState, useEffect, useRef, useCallback } from 'react';
|
||||
import throttle from 'lodash/throttle';
|
||||
import isEqualWith from 'lodash/isEqualWith';
|
||||
import isEqual from 'lodash/isEqual';
|
||||
import { useApolloClient } from '@apollo/client';
|
||||
import { usePrevious } from './use-previous';
|
||||
import type { OperationVariables } from '@apollo/client';
|
||||
import type { Subscribe, Load, UpdateCallback } from '@vegaprotocol/utils';
|
||||
import { variablesIsEqualCustomizer } from '@vegaprotocol/utils';
|
||||
|
||||
export interface useDataProviderParams<
|
||||
Data,
|
||||
@@ -62,19 +62,13 @@ export const useDataProvider = <
|
||||
const flushRef = useRef<(() => void) | undefined>(undefined);
|
||||
const reloadRef = useRef<((force?: boolean) => void) | undefined>(undefined);
|
||||
const loadRef = useRef<Load<Data> | undefined>(undefined);
|
||||
const variablesRef = useRef<Variables>(props.variables);
|
||||
const variables = useMemo(() => {
|
||||
if (
|
||||
!isEqualWith(
|
||||
variablesRef.current,
|
||||
props.variables,
|
||||
variablesIsEqualCustomizer
|
||||
)
|
||||
) {
|
||||
variablesRef.current = props.variables;
|
||||
const prevVariables = usePrevious(props.variables);
|
||||
const [variables, setVariables] = useState(props.variables);
|
||||
useEffect(() => {
|
||||
if (!isEqual(prevVariables, props.variables)) {
|
||||
setVariables(props.variables);
|
||||
}
|
||||
return variablesRef.current;
|
||||
}, [props.variables]);
|
||||
}, [props.variables, prevVariables]);
|
||||
const flush = useCallback(() => {
|
||||
if (flushRef.current) {
|
||||
flushRef.current();
|
||||
|
||||
@@ -45,7 +45,7 @@ type CombinedData = {
|
||||
|
||||
type SubscriptionData = QueryData;
|
||||
type Delta = Data;
|
||||
type Variables = { var: string; filter?: string[] };
|
||||
type Variables = { var: string };
|
||||
|
||||
const update = jest.fn<
|
||||
ReturnType<Update<Data, Delta, Variables>>,
|
||||
@@ -231,14 +231,10 @@ describe('data provider', () => {
|
||||
clientSubscribeSubscribe.mockClear();
|
||||
});
|
||||
it('memoize instance and unsubscribe if no subscribers', () => {
|
||||
const subscription1 = subscribe(jest.fn(), client, {
|
||||
...variables,
|
||||
filter: ['1', '2'],
|
||||
});
|
||||
const subscription2 = subscribe(jest.fn(), client, {
|
||||
...variables,
|
||||
filter: ['2', '1'],
|
||||
});
|
||||
const subscription1 = subscribe(jest.fn(), client, variables);
|
||||
const subscription2 = subscribe(jest.fn(), client, { ...variables });
|
||||
// const subscription1 = subscribe(jest.fn(), client);
|
||||
// const subscription2 = subscribe(jest.fn(), client);
|
||||
expect(clientSubscribeSubscribe.mock.calls.length).toEqual(1);
|
||||
subscription1.unsubscribe();
|
||||
expect(clientSubscribeUnsubscribe.mock.calls.length).toEqual(0);
|
||||
|
||||
@@ -10,7 +10,7 @@ import type {
|
||||
} from '@apollo/client';
|
||||
import type { GraphQLErrors } from '@apollo/client/errors';
|
||||
import type { Subscription } from 'zen-observable-ts';
|
||||
import isEqualWith from 'lodash/isEqualWith';
|
||||
import isEqual from 'lodash/isEqual';
|
||||
import { isNotFoundGraphQLError } from './apollo-client';
|
||||
import type * as Schema from '@vegaprotocol/types';
|
||||
interface UpdateData<Data, Delta> {
|
||||
@@ -104,11 +104,7 @@ interface GetTotalCount<QueryData> {
|
||||
}
|
||||
|
||||
interface GetDelta<SubscriptionData, Delta, Variables> {
|
||||
(
|
||||
subscriptionData: SubscriptionData,
|
||||
variables: Variables,
|
||||
client: ApolloClient<object>
|
||||
): Delta;
|
||||
(subscriptionData: SubscriptionData, variables?: Variables): Delta;
|
||||
}
|
||||
|
||||
export type Node = { id: string };
|
||||
@@ -424,7 +420,7 @@ function makeDataProviderInternal<
|
||||
if (!subscriptionData || !getDelta || !update) {
|
||||
return;
|
||||
}
|
||||
const delta = getDelta(subscriptionData, variables, client);
|
||||
const delta = getDelta(subscriptionData, variables);
|
||||
if (loading) {
|
||||
updateQueue.push(delta);
|
||||
} else {
|
||||
@@ -516,26 +512,11 @@ function makeDataProviderInternal<
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares two arrays assuming that they are sets of primitive values, used to compare gql query variables
|
||||
*/
|
||||
export const variablesIsEqualCustomizer: NonNullable<
|
||||
Parameters<typeof isEqualWith>['2']
|
||||
> = (value, other) => {
|
||||
if (Array.isArray(value) && Array.isArray(other)) {
|
||||
return (
|
||||
value.length === other.length &&
|
||||
new Set([...value, ...other]).size === value.length
|
||||
);
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
/**
|
||||
* Memoizes data provider instances using query variables as cache key
|
||||
*
|
||||
* @param fn
|
||||
* @returns subscribe function
|
||||
* @returns subscibe function
|
||||
*/
|
||||
const memoize = <
|
||||
Data,
|
||||
@@ -549,9 +530,7 @@ const memoize = <
|
||||
variables?: Variables;
|
||||
}[] = [];
|
||||
return (variables?: Variables) => {
|
||||
const cached = cache.find((c) =>
|
||||
isEqualWith(c.variables, variables, variablesIsEqualCustomizer)
|
||||
);
|
||||
const cached = cache.find((c) => isEqual(c.variables, variables));
|
||||
if (cached) {
|
||||
return cached.subscribe;
|
||||
}
|
||||
@@ -603,10 +582,8 @@ export function makeDataProvider<
|
||||
const getInstance = memoize<Data, Delta, Variables>(() =>
|
||||
makeDataProviderInternal(params)
|
||||
);
|
||||
return (callback, client, variables) => {
|
||||
const instance = getInstance(variables)(callback, client, variables);
|
||||
return instance;
|
||||
};
|
||||
return (callback, client, variables) =>
|
||||
getInstance(variables)(callback, client, variables);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -628,9 +605,7 @@ export type CombineDerivedData<
|
||||
> = (
|
||||
data: DerivedPart<Variables>['data'][],
|
||||
variables: Variables,
|
||||
prevData: Data | null,
|
||||
parts: DerivedPart<Variables>[],
|
||||
subscriptions?: ReturnType<DependencySubscribe<Variables>>[]
|
||||
prevData: Data | null
|
||||
) => Data | null;
|
||||
|
||||
export type CombineDerivedDelta<
|
||||
@@ -712,9 +687,7 @@ function makeDerivedDataProviderInternal<
|
||||
? combineData(
|
||||
parts.map((part) => part.data),
|
||||
variables,
|
||||
data,
|
||||
parts,
|
||||
subscriptions
|
||||
data
|
||||
)
|
||||
: data;
|
||||
if (
|
||||
|
||||
Reference in New Issue
Block a user