Merge branch 'master' into task/token-flow-tests
This commit is contained in:
commit
c8bcc60a19
30
apps/simple-trading-app-e2e/src/integration/header.test.ts
Normal file
30
apps/simple-trading-app-e2e/src/integration/header.test.ts
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
describe('console lite header', () => {
|
||||||
|
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');
|
||||||
|
});
|
||||||
|
});
|
4
apps/simple-trading-app/netlify.toml
Normal file
4
apps/simple-trading-app/netlify.toml
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
[[redirects]]
|
||||||
|
from = "/*"
|
||||||
|
to = "/index.html"
|
||||||
|
status = 200
|
@ -68,6 +68,15 @@
|
|||||||
"jestConfig": "apps/simple-trading-app/jest.config.js",
|
"jestConfig": "apps/simple-trading-app/jest.config.js",
|
||||||
"passWithNoTests": true
|
"passWithNoTests": true
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"build-netlify": {
|
||||||
|
"builder": "@nrwl/workspace:run-commands",
|
||||||
|
"options": {
|
||||||
|
"commands": [
|
||||||
|
"cp apps/simple-trading-app/netlify.toml netlify.toml",
|
||||||
|
"nx build simple-trading-app"
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"tags": []
|
"tags": []
|
||||||
|
@ -8,13 +8,11 @@ import {
|
|||||||
VegaManageDialog,
|
VegaManageDialog,
|
||||||
VegaWalletProvider,
|
VegaWalletProvider,
|
||||||
} from '@vegaprotocol/wallet';
|
} from '@vegaprotocol/wallet';
|
||||||
import { VegaWalletConnectButton } from './components/vega-wallet-connect-button';
|
|
||||||
import { ThemeSwitcher } from '@vegaprotocol/ui-toolkit';
|
|
||||||
import { Connectors } from './lib/vega-connectors';
|
import { Connectors } from './lib/vega-connectors';
|
||||||
import '../styles.scss';
|
import '../styles.scss';
|
||||||
import { AppLoader } from './components/app-loader';
|
import { AppLoader } from './components/app-loader';
|
||||||
|
import Header from './components/header';
|
||||||
import { Main } from './components/main';
|
import { Main } from './components/main';
|
||||||
import { DrawerToggle, DRAWER_TOGGLE_VARIANTS } from './components/drawer';
|
|
||||||
import { useLocation } from 'react-router-dom';
|
import { useLocation } from 'react-router-dom';
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
@ -39,32 +37,12 @@ function App() {
|
|||||||
<NetworkLoader createClient={createClient}>
|
<NetworkLoader createClient={createClient}>
|
||||||
<VegaWalletProvider>
|
<VegaWalletProvider>
|
||||||
<AppLoader>
|
<AppLoader>
|
||||||
<div className="max-h-full min-h-full dark:bg-black dark:text-white-60 bg-white text-black-60 grid grid-rows-[min-content,1fr]">
|
<div className="max-h-full min-h-full dark:bg-lite-black dark:text-white-60 bg-white text-black-60 grid grid-rows-[min-content,1fr]">
|
||||||
<div className="flex items-stretch p-16 bg-black text-white-60">
|
<Header
|
||||||
<div className="flex items-center gap-4 ml-auto mr-8">
|
setVegaWallet={setVegaWallet}
|
||||||
<VegaWalletConnectButton
|
toggleTheme={toggleTheme}
|
||||||
setConnectDialog={(open) =>
|
/>
|
||||||
setVegaWallet((x) => ({ ...x, connect: open }))
|
|
||||||
}
|
|
||||||
setManageDialog={(open) =>
|
|
||||||
setVegaWallet((x) => ({ ...x, manage: open }))
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<ThemeSwitcher
|
|
||||||
onToggle={toggleTheme}
|
|
||||||
className="-my-4"
|
|
||||||
sunClassName="text-white"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<DrawerToggle
|
|
||||||
onToggle={onToggle}
|
|
||||||
variant={DRAWER_TOGGLE_VARIANTS.OPEN}
|
|
||||||
className="xs:py-32 xs:px-16 xs:text-white xs:hover:text-blue"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Main isMenuOpen={menuOpen} onToggle={onToggle} />
|
<Main isMenuOpen={menuOpen} onToggle={onToggle} />
|
||||||
|
|
||||||
<VegaConnectDialog
|
<VegaConnectDialog
|
||||||
connectors={Connectors}
|
connectors={Connectors}
|
||||||
dialogOpen={vegaWallet.connect}
|
dialogOpen={vegaWallet.connect}
|
||||||
|
@ -0,0 +1,36 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import Video from '../header/video';
|
||||||
|
import Comet from '../header/comet';
|
||||||
|
import Star from '../icons/star';
|
||||||
|
|
||||||
|
const Baubles = () => {
|
||||||
|
return (
|
||||||
|
<div 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>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Baubles;
|
@ -1,3 +1,4 @@
|
|||||||
|
import * as React from 'react';
|
||||||
import { useParams } from 'react-router-dom';
|
import { useParams } from 'react-router-dom';
|
||||||
import {
|
import {
|
||||||
DealTicketManager,
|
DealTicketManager,
|
||||||
@ -8,6 +9,7 @@ import { useVegaWallet } from '@vegaprotocol/wallet';
|
|||||||
import { gql, useQuery } from '@apollo/client';
|
import { gql, useQuery } from '@apollo/client';
|
||||||
import { DealTicketBalance } from './deal-ticket-balance';
|
import { DealTicketBalance } from './deal-ticket-balance';
|
||||||
import type { PartyBalanceQuery } from './__generated__/PartyBalanceQuery';
|
import type { PartyBalanceQuery } from './__generated__/PartyBalanceQuery';
|
||||||
|
import Baubles from './baubles-decor';
|
||||||
|
|
||||||
const tempEmptyText = <p>Please select a market from the markets page</p>;
|
const tempEmptyText = <p>Please select a market from the markets page</p>;
|
||||||
|
|
||||||
@ -39,27 +41,34 @@ export const DealTicketContainer = () => {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
return marketId ? (
|
return (
|
||||||
<Container marketId={marketId}>
|
<div className="flex">
|
||||||
{(data) => (
|
<div className="md:w-1/2 md:min-w-[500px]">
|
||||||
<DealTicketManager market={data.market}>
|
{marketId ? (
|
||||||
{loading ? (
|
<Container marketId={marketId}>
|
||||||
'Loading...'
|
{(data) => (
|
||||||
) : (
|
<DealTicketManager market={data.market}>
|
||||||
<DealTicketBalance
|
{loading ? (
|
||||||
settlementAsset={
|
'Loading...'
|
||||||
data.market.tradableInstrument.instrument.product
|
) : (
|
||||||
?.settlementAsset
|
<DealTicketBalance
|
||||||
}
|
settlementAsset={
|
||||||
accounts={partyData?.party?.accounts || []}
|
data.market.tradableInstrument.instrument.product
|
||||||
isWalletConnected={!!keypair?.pub}
|
?.settlementAsset
|
||||||
/>
|
}
|
||||||
)}
|
accounts={partyData?.party?.accounts || []}
|
||||||
<DealTicketSteps market={data.market} />
|
isWalletConnected={!!keypair?.pub}
|
||||||
</DealTicketManager>
|
/>
|
||||||
)}
|
)}
|
||||||
</Container>
|
<DealTicketSteps market={data.market} />
|
||||||
) : (
|
</DealTicketManager>
|
||||||
tempEmptyText
|
)}
|
||||||
|
</Container>
|
||||||
|
) : (
|
||||||
|
tempEmptyText
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<Baubles />
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -8,6 +8,6 @@ interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const DrawerWrapper = ({ children, className = '' }: Props) => {
|
export const DrawerWrapper = ({ children, className = '' }: Props) => {
|
||||||
const classes = classNames('flex dark:bg-black md:flex-row', className);
|
const classes = classNames('flex dark:bg-lite-black md:flex-row', className);
|
||||||
return <div className={classes}>{children}</div>;
|
return <div className={classes}>{children}</div>;
|
||||||
};
|
};
|
||||||
|
@ -34,11 +34,14 @@ export const NavigationDrawer = ({
|
|||||||
|
|
||||||
const translateClose = rtl ? 'translate-x-full' : '-translate-x-full';
|
const translateClose = rtl ? 'translate-x-full' : '-translate-x-full';
|
||||||
|
|
||||||
const innerStyles = classNames('w-3/4 md:w-full bg-white dark:bg-black', {
|
const innerStyles = classNames(
|
||||||
'translate-x-0 transition-transform md:transform-none': isMenuOpen,
|
'w-3/4 md:w-full bg-white dark:bg-lite-black',
|
||||||
[`${translateClose} md:transform-none`]: !isMenuOpen,
|
{
|
||||||
[innerClasses]: innerClasses,
|
'translate-x-0 transition-transform md:transform-none': isMenuOpen,
|
||||||
});
|
[`${translateClose} md:transform-none`]: !isMenuOpen,
|
||||||
|
[innerClasses]: innerClasses,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<aside aria-label="Sidebar Navigation Menu" className={outerStyles}>
|
<aside aria-label="Sidebar Navigation Menu" className={outerStyles}>
|
||||||
|
48
apps/simple-trading-app/src/app/components/header/comet.tsx
Normal file
48
apps/simple-trading-app/src/app/components/header/comet.tsx
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
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;
|
41
apps/simple-trading-app/src/app/components/header/header.tsx
Normal file
41
apps/simple-trading-app/src/app/components/header/header.tsx
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { ThemeSwitcher } from '@vegaprotocol/ui-toolkit';
|
||||||
|
import Logo from './logo';
|
||||||
|
import { VegaWalletConnectButton } from '../vega-wallet-connect-button';
|
||||||
|
|
||||||
|
type WalletParams = {
|
||||||
|
connect: boolean;
|
||||||
|
manage: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
setVegaWallet: (func: (wParams: WalletParams) => WalletParams) => void;
|
||||||
|
toggleTheme: () => void;
|
||||||
|
}
|
||||||
|
const Header = ({ setVegaWallet, toggleTheme }: Props) => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className="flex items-stretch pr-16 py-16 bg-black text-white-60"
|
||||||
|
data-testid="header"
|
||||||
|
>
|
||||||
|
<Logo />
|
||||||
|
<div className="flex items-center gap-4 ml-auto mr-8 relative z-10">
|
||||||
|
<VegaWalletConnectButton
|
||||||
|
setConnectDialog={(open) =>
|
||||||
|
setVegaWallet((x) => ({ ...x, connect: open }))
|
||||||
|
}
|
||||||
|
setManageDialog={(open) =>
|
||||||
|
setVegaWallet((x) => ({ ...x, manage: open }))
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<ThemeSwitcher
|
||||||
|
onToggle={toggleTheme}
|
||||||
|
className="-my-4"
|
||||||
|
sunClassName="text-white"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Header;
|
@ -0,0 +1 @@
|
|||||||
|
export { default } from './header';
|
18
apps/simple-trading-app/src/app/components/header/logo.tsx
Normal file
18
apps/simple-trading-app/src/app/components/header/logo.tsx
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
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-20 text-white"
|
||||||
|
aria-label={t('Go to home page')}
|
||||||
|
to="/"
|
||||||
|
>
|
||||||
|
<VLogo />
|
||||||
|
</NavLink>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Logo;
|
33
apps/simple-trading-app/src/app/components/header/video.tsx
Normal file
33
apps/simple-trading-app/src/app/components/header/video.tsx
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
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,8 +1,8 @@
|
|||||||
export const LiquidityIconPath = () => (
|
export const LiquidityIconPath = () => (
|
||||||
<>
|
<>
|
||||||
<path
|
<path
|
||||||
fill-rule="evenodd"
|
fillRule="evenodd"
|
||||||
clip-rule="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"
|
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="11.5" y="17.4" width="1" height="1" />
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
export const MarketIconPath = () => (
|
export const MarketIconPath = () => (
|
||||||
<>
|
<>
|
||||||
<path
|
<path
|
||||||
fill-rule="evenodd"
|
fillRule="evenodd"
|
||||||
clip-rule="evenodd"
|
clipRule="evenodd"
|
||||||
d="M3.5 2H2V20.5V22H3.5H22V20.5H3.5V2Z"
|
d="M3.5 2H2V20.5V22H3.5H22V20.5H3.5V2Z"
|
||||||
/>
|
/>
|
||||||
<rect x="5" y="15" width="2" height="2" />
|
<rect x="5" y="15" width="2" height="2" />
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
export const PortfolioIconPath = () => (
|
export const PortfolioIconPath = () => (
|
||||||
<>
|
<>
|
||||||
<path
|
<path
|
||||||
fill-rule="evenodd"
|
fillRule="evenodd"
|
||||||
clip-rule="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"
|
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="4" y="8" width="2" height="2" />
|
||||||
|
20
apps/simple-trading-app/src/app/components/icons/star.tsx
Normal file
20
apps/simple-trading-app/src/app/components/icons/star.tsx
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
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,13 +1,13 @@
|
|||||||
export const TradeIconPath = () => (
|
export const TradeIconPath = () => (
|
||||||
<>
|
<>
|
||||||
<path
|
<path
|
||||||
fill-rule="evenodd"
|
fillRule="evenodd"
|
||||||
clip-rule="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"
|
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
|
<path
|
||||||
fill-rule="evenodd"
|
fillRule="evenodd"
|
||||||
clip-rule="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"
|
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"
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
|
@ -73,6 +73,7 @@ export const agGridLightVariables = `
|
|||||||
|
|
||||||
export const agGridDarkVariables = `
|
export const agGridDarkVariables = `
|
||||||
.ag-theme-balham-dark {
|
.ag-theme-balham-dark {
|
||||||
|
--ag-background-color: ${theme.colors.lite.black};
|
||||||
--ag-row-border-color: ${theme.colors.transparent};
|
--ag-row-border-color: ${theme.colors.transparent};
|
||||||
--ag-row-hover-color: ${theme.colors.transparent};
|
--ag-row-hover-color: ${theme.colors.transparent};
|
||||||
--ag-font-size: 15px;
|
--ag-font-size: 15px;
|
||||||
|
@ -91,14 +91,15 @@ export const FILTERS_QUERY = gql`
|
|||||||
const update = (
|
const update = (
|
||||||
data: SimpleMarkets_markets[],
|
data: SimpleMarkets_markets[],
|
||||||
delta: SimpleMarketDataSub_marketData
|
delta: SimpleMarketDataSub_marketData
|
||||||
) =>
|
) => {
|
||||||
produce(data, (draft) => {
|
return produce(data, (draft) => {
|
||||||
const index = draft.findIndex((m) => m.id === delta.market.id);
|
const index = draft.findIndex((m) => m.id === delta.market.id);
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
draft[index].data = delta;
|
draft[index].data = delta;
|
||||||
}
|
}
|
||||||
// @TODO - else push new market to draft
|
// @TODO - else push new market to draft
|
||||||
});
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const getData = (responseData: SimpleMarkets) => responseData.markets;
|
const getData = (responseData: SimpleMarkets) => responseData.markets;
|
||||||
const getDelta = (
|
const getDelta = (
|
||||||
|
@ -16,11 +16,11 @@ import { ThemeContext } from '@vegaprotocol/react-helpers';
|
|||||||
import type { MarketState } from '@vegaprotocol/types';
|
import type { MarketState } from '@vegaprotocol/types';
|
||||||
import useMarketsFilterData from '../../hooks/use-markets-filter-data';
|
import useMarketsFilterData from '../../hooks/use-markets-filter-data';
|
||||||
import useColumnDefinitions from '../../hooks/use-column-definitions';
|
import useColumnDefinitions from '../../hooks/use-column-definitions';
|
||||||
import DataProvider from './data-provider';
|
import dataProvider from './data-provider';
|
||||||
import * as constants from './constants';
|
import * as constants from './constants';
|
||||||
import SimpleMarketToolbar from './simple-market-toolbar';
|
import SimpleMarketToolbar from './simple-market-toolbar';
|
||||||
import type { SimpleMarkets_markets } from './__generated__/SimpleMarkets';
|
import type { SimpleMarkets_markets } from './__generated__/SimpleMarkets';
|
||||||
|
import type { SimpleMarketDataSub_marketData } from './__generated__/SimpleMarketDataSub';
|
||||||
export type SimpleMarketsType = SimpleMarkets_markets & {
|
export type SimpleMarketsType = SimpleMarkets_markets & {
|
||||||
percentChange?: number | '-';
|
percentChange?: number | '-';
|
||||||
};
|
};
|
||||||
@ -44,15 +44,16 @@ const SimpleMarketList = () => {
|
|||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
const update = useCallback(
|
const update = useCallback(
|
||||||
(delta) => statusesRef.current[delta.market.id] === delta.market.state,
|
({ delta }: { delta: SimpleMarketDataSub_marketData }) =>
|
||||||
|
statusesRef.current[delta.market.id] === delta.market.state,
|
||||||
[statusesRef]
|
[statusesRef]
|
||||||
);
|
);
|
||||||
|
|
||||||
const { data, error, loading } = useDataProvider(
|
const { data, error, loading } = useDataProvider({
|
||||||
DataProvider,
|
dataProvider,
|
||||||
update,
|
update,
|
||||||
variables
|
variables,
|
||||||
);
|
});
|
||||||
const localData: Array<SimpleMarketsType> = useMarketsFilterData(
|
const localData: Array<SimpleMarketsType> = useMarketsFilterData(
|
||||||
data || [],
|
data || [],
|
||||||
params
|
params
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { render, screen } from '@testing-library/react';
|
import { render, screen } from '@testing-library/react';
|
||||||
import { themelite as theme } from '@vegaprotocol/tailwindcss-config';
|
|
||||||
import { MockedProvider } from '@apollo/react-testing';
|
import { MockedProvider } from '@apollo/react-testing';
|
||||||
import SimpleMarketPercentChange from './simple-market-percent-change';
|
import SimpleMarketPercentChange from './simple-market-percent-change';
|
||||||
import type { SimpleMarkets_markets_candles } from './__generated__/SimpleMarkets';
|
import type { SimpleMarkets_markets_candles } from './__generated__/SimpleMarkets';
|
||||||
@ -50,8 +49,8 @@ describe('SimpleMarketPercentChange should parse proper change', () => {
|
|||||||
</MockedProvider>
|
</MockedProvider>
|
||||||
);
|
);
|
||||||
expect(screen.getByText('100.000%')).toBeInTheDocument();
|
expect(screen.getByText('100.000%')).toBeInTheDocument();
|
||||||
expect(screen.getByText('100.000%')).toHaveStyle(
|
expect(screen.getByText('100.000%')).toHaveClass(
|
||||||
`color: ${theme.colors.vega.green}`
|
'text-darkerGreen dark:text-lightGreen'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it('a depreciated one', () => {
|
it('a depreciated one', () => {
|
||||||
@ -70,8 +69,6 @@ describe('SimpleMarketPercentChange should parse proper change', () => {
|
|||||||
</MockedProvider>
|
</MockedProvider>
|
||||||
);
|
);
|
||||||
expect(screen.getByText('-50.000%')).toBeInTheDocument();
|
expect(screen.getByText('-50.000%')).toBeInTheDocument();
|
||||||
expect(screen.getByText('-50.000%')).toHaveStyle(
|
expect(screen.getByText('-50.000%')).toHaveClass('text-vega-pink');
|
||||||
`color: ${theme.colors.vega.pink}`
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
|
import classNames from 'classnames';
|
||||||
import { InView } from 'react-intersection-observer';
|
import { InView } from 'react-intersection-observer';
|
||||||
import { useSubscription } from '@apollo/client';
|
import { useSubscription } from '@apollo/client';
|
||||||
import { themelite as theme } from '@vegaprotocol/tailwindcss-config';
|
|
||||||
import type { SimpleMarkets_markets_candles } from './__generated__/SimpleMarkets';
|
import type { SimpleMarkets_markets_candles } from './__generated__/SimpleMarkets';
|
||||||
import type {
|
import type {
|
||||||
CandleLive,
|
CandleLive,
|
||||||
@ -37,14 +37,14 @@ const getChange = (
|
|||||||
return ' - ';
|
return ' - ';
|
||||||
};
|
};
|
||||||
|
|
||||||
const getColor = (change: number | string) => {
|
const getClassColor = (change: number | string) => {
|
||||||
if (parseFloat(change as string) > 0) {
|
if (parseFloat(change as string) > 0) {
|
||||||
return theme.colors.vega.green;
|
return 'text-darkerGreen dark:text-lightGreen';
|
||||||
}
|
}
|
||||||
if (parseFloat(change as string) < 0) {
|
if (parseFloat(change as string) < 0) {
|
||||||
return theme.colors.vega.pink;
|
return 'text-vega-pink';
|
||||||
}
|
}
|
||||||
return theme.colors.black[10];
|
return 'text-black-10';
|
||||||
};
|
};
|
||||||
|
|
||||||
const SimpleMarketPercentChangeWrapper = (props: Props) => {
|
const SimpleMarketPercentChangeWrapper = (props: Props) => {
|
||||||
@ -67,16 +67,14 @@ const SimpleMarketPercentChange = ({ candles, marketId, setValue }: Props) => {
|
|||||||
variables: { marketId },
|
variables: { marketId },
|
||||||
});
|
});
|
||||||
const change = getChange(candles, close);
|
const change = getChange(candles, close);
|
||||||
const color = getColor(change);
|
const colorClasses = getClassColor(change);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const value = parseFloat(change);
|
const value = parseFloat(change);
|
||||||
setValue(isNaN(value) ? '-' : value);
|
setValue(isNaN(value) ? '-' : value);
|
||||||
}, [setValue, change]);
|
}, [setValue, change]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex text-center" style={{ color }}>
|
<div className={classNames('flex text-center', colorClasses)}>{change}</div>
|
||||||
{change}
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -38,7 +38,7 @@
|
|||||||
"tranche_end": "2022-11-26T13:48:10.000Z",
|
"tranche_end": "2022-11-26T13:48:10.000Z",
|
||||||
"total_added": "100",
|
"total_added": "100",
|
||||||
"total_removed": "0",
|
"total_removed": "0",
|
||||||
"locked_amount": "40.63611745306951",
|
"locked_amount": "39.19756468797565",
|
||||||
"deposits": [
|
"deposits": [
|
||||||
{
|
{
|
||||||
"amount": "100",
|
"amount": "100",
|
||||||
@ -242,7 +242,7 @@
|
|||||||
"tranche_end": "2022-10-12T00:53:20.000Z",
|
"tranche_end": "2022-10-12T00:53:20.000Z",
|
||||||
"total_added": "1100",
|
"total_added": "1100",
|
||||||
"total_removed": "673.04388635",
|
"total_removed": "673.04388635",
|
||||||
"locked_amount": "309.75924657534241",
|
"locked_amount": "293.93516615930995",
|
||||||
"deposits": [
|
"deposits": [
|
||||||
{
|
{
|
||||||
"amount": "1000",
|
"amount": "1000",
|
||||||
|
@ -69,7 +69,7 @@
|
|||||||
"tranche_end": "2022-10-12T00:53:20.000Z",
|
"tranche_end": "2022-10-12T00:53:20.000Z",
|
||||||
"total_added": "1010.000000000000000001",
|
"total_added": "1010.000000000000000001",
|
||||||
"total_removed": "668.4622323651",
|
"total_removed": "668.4622323651",
|
||||||
"locked_amount": "284.4153082191780310002815993150684931",
|
"locked_amount": "269.8859252917300450002672137874175545",
|
||||||
"deposits": [
|
"deposits": [
|
||||||
{
|
{
|
||||||
"amount": "1000",
|
"amount": "1000",
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
/>
|
/>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<meta name="theme-color" content="#000000" />
|
<meta name="theme-color" content="#000000" />
|
||||||
<meta name="description" content="Health check for Vega" />
|
<meta name="description" content="Vega Protocol - VEGA Token Vesting" />
|
||||||
<link rel="apple-touch-icon" href="assets/apple-touch-icon.png" />
|
<link rel="apple-touch-icon" href="assets/apple-touch-icon.png" />
|
||||||
<!--
|
<!--
|
||||||
manifest.json provides metadata used when your web app is installed on a
|
manifest.json provides metadata used when your web app is installed on a
|
||||||
|
@ -55,8 +55,8 @@ export const getId = (
|
|||||||
const update = (
|
const update = (
|
||||||
data: Accounts_party_accounts[],
|
data: Accounts_party_accounts[],
|
||||||
delta: AccountSubscribe_accounts
|
delta: AccountSubscribe_accounts
|
||||||
) =>
|
) => {
|
||||||
produce(data, (draft) => {
|
return produce(data, (draft) => {
|
||||||
const id = getId(delta);
|
const id = getId(delta);
|
||||||
const index = draft.findIndex((a) => getId(a) === id);
|
const index = draft.findIndex((a) => getId(a) === id);
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
@ -65,6 +65,8 @@ const update = (
|
|||||||
draft.push(delta);
|
draft.push(delta);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const getData = (responseData: Accounts): Accounts_party_accounts[] | null =>
|
const getData = (responseData: Accounts): Accounts_party_accounts[] | null =>
|
||||||
responseData.party ? responseData.party.accounts : null;
|
responseData.party ? responseData.party.accounts : null;
|
||||||
const getDelta = (
|
const getDelta = (
|
||||||
|
@ -22,7 +22,7 @@ export const AccountsManager = ({ partyId }: AccountsManagerProps) => {
|
|||||||
const gridRef = useRef<AgGridReact | null>(null);
|
const gridRef = useRef<AgGridReact | null>(null);
|
||||||
const variables = useMemo(() => ({ partyId }), [partyId]);
|
const variables = useMemo(() => ({ partyId }), [partyId]);
|
||||||
const update = useCallback(
|
const update = useCallback(
|
||||||
(delta: AccountSubscribe_accounts) => {
|
({ delta }: { delta: AccountSubscribe_accounts }) => {
|
||||||
const update: Accounts_party_accounts[] = [];
|
const update: Accounts_party_accounts[] = [];
|
||||||
const add: Accounts_party_accounts[] = [];
|
const add: Accounts_party_accounts[] = [];
|
||||||
if (!gridRef.current) {
|
if (!gridRef.current) {
|
||||||
@ -64,7 +64,7 @@ export const AccountsManager = ({ partyId }: AccountsManagerProps) => {
|
|||||||
const { data, error, loading } = useDataProvider<
|
const { data, error, loading } = useDataProvider<
|
||||||
Accounts_party_accounts[],
|
Accounts_party_accounts[],
|
||||||
AccountSubscribe_accounts
|
AccountSubscribe_accounts
|
||||||
>(accountsDataProvider, update, variables);
|
>({ dataProvider: accountsDataProvider, update, variables });
|
||||||
return (
|
return (
|
||||||
<AsyncRenderer loading={loading} error={error} data={data}>
|
<AsyncRenderer loading={loading} error={error} data={data}>
|
||||||
<AccountsTable ref={gridRef} data={data} />
|
<AccountsTable ref={gridRef} data={data} />
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
|
import produce from 'immer';
|
||||||
import { gql } from '@apollo/client';
|
import { gql } from '@apollo/client';
|
||||||
import { makeDataProvider } from '@vegaprotocol/react-helpers';
|
import { makeDataProvider } from '@vegaprotocol/react-helpers';
|
||||||
import produce from 'immer';
|
import type { PageInfo, Pagination } from '@vegaprotocol/react-helpers';
|
||||||
import type { FillFields } from './__generated__/FillFields';
|
import type { FillFields } from './__generated__/FillFields';
|
||||||
import type {
|
import type {
|
||||||
Fills,
|
Fills,
|
||||||
Fills_party_tradesPaged_edges_node,
|
Fills_party_tradesPaged_edges,
|
||||||
} from './__generated__/Fills';
|
} from './__generated__/Fills';
|
||||||
import type { FillsSub } from './__generated__/FillsSub';
|
import type { FillsSub } from './__generated__/FillsSub';
|
||||||
|
|
||||||
@ -16,41 +17,19 @@ const FILL_FRAGMENT = gql`
|
|||||||
size
|
size
|
||||||
buyOrder
|
buyOrder
|
||||||
sellOrder
|
sellOrder
|
||||||
aggressor
|
|
||||||
buyer {
|
buyer {
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
seller {
|
seller {
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
buyerFee {
|
|
||||||
makerFee
|
|
||||||
infrastructureFee
|
|
||||||
liquidityFee
|
|
||||||
}
|
|
||||||
sellerFee {
|
|
||||||
makerFee
|
|
||||||
infrastructureFee
|
|
||||||
liquidityFee
|
|
||||||
}
|
|
||||||
market {
|
market {
|
||||||
id
|
id
|
||||||
name
|
|
||||||
decimalPlaces
|
decimalPlaces
|
||||||
positionDecimalPlaces
|
|
||||||
tradableInstrument {
|
tradableInstrument {
|
||||||
instrument {
|
instrument {
|
||||||
id
|
id
|
||||||
code
|
code
|
||||||
product {
|
|
||||||
... on Future {
|
|
||||||
settlementAsset {
|
|
||||||
id
|
|
||||||
symbol
|
|
||||||
decimals
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -88,30 +67,69 @@ export const FILLS_SUB = gql`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const update = (data: FillFields[], delta: FillFields[]) => {
|
const update = (data: Fills_party_tradesPaged_edges[], delta: FillFields[]) => {
|
||||||
// Add or update incoming trades
|
|
||||||
return produce(data, (draft) => {
|
return produce(data, (draft) => {
|
||||||
delta.forEach((trade) => {
|
delta.forEach((node) => {
|
||||||
const index = draft.findIndex((t) => t.id === trade.id);
|
const index = draft.findIndex((edge) => edge.node.id === node.id);
|
||||||
if (index === -1) {
|
if (index !== -1) {
|
||||||
draft.unshift(trade);
|
Object.assign(draft[index].node, node);
|
||||||
} else {
|
} else {
|
||||||
draft[index] = trade;
|
draft.unshift({ node, cursor: '', __typename: 'TradeEdge' });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const getData = (
|
const getData = (responseData: Fills): Fills_party_tradesPaged_edges[] | null =>
|
||||||
responseData: Fills
|
responseData.party?.tradesPaged.edges || null;
|
||||||
): Fills_party_tradesPaged_edges_node[] | null =>
|
|
||||||
responseData.party?.tradesPaged.edges.map((e) => e.node) || null;
|
const getPageInfo = (responseData: Fills): PageInfo | null =>
|
||||||
|
responseData.party?.tradesPaged.pageInfo || null;
|
||||||
|
|
||||||
|
const getTotalCount = (responseData: Fills): number | undefined =>
|
||||||
|
responseData.party?.tradesPaged.totalCount;
|
||||||
|
|
||||||
const getDelta = (subscriptionData: FillsSub) => subscriptionData.trades || [];
|
const getDelta = (subscriptionData: FillsSub) => subscriptionData.trades || [];
|
||||||
|
|
||||||
|
const append = (
|
||||||
|
data: Fills_party_tradesPaged_edges[] | null,
|
||||||
|
pageInfo: PageInfo,
|
||||||
|
insertionData: Fills_party_tradesPaged_edges[] | null,
|
||||||
|
insertionPageInfo: PageInfo | null,
|
||||||
|
pagination?: Pagination
|
||||||
|
) => {
|
||||||
|
if (data && insertionData && insertionPageInfo) {
|
||||||
|
if (pagination?.after) {
|
||||||
|
if (data[data.length - 1].cursor === pagination.after) {
|
||||||
|
return {
|
||||||
|
data: [...data, ...insertionData],
|
||||||
|
pageInfo: { ...pageInfo, endCursor: insertionPageInfo.endCursor },
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
const cursors = data.map((item) => item.cursor);
|
||||||
|
const startIndex = cursors.lastIndexOf(pagination.after);
|
||||||
|
if (startIndex !== -1) {
|
||||||
|
return {
|
||||||
|
data: [...data.slice(0, startIndex), ...insertionData],
|
||||||
|
pageInfo: { ...pageInfo, endCursor: insertionPageInfo.endCursor },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return { data, pageInfo };
|
||||||
|
};
|
||||||
|
|
||||||
export const fillsDataProvider = makeDataProvider(
|
export const fillsDataProvider = makeDataProvider(
|
||||||
FILLS_QUERY,
|
FILLS_QUERY,
|
||||||
FILLS_SUB,
|
FILLS_SUB,
|
||||||
update,
|
update,
|
||||||
getData,
|
getData,
|
||||||
getDelta
|
getDelta,
|
||||||
|
{
|
||||||
|
getPageInfo,
|
||||||
|
getTotalCount,
|
||||||
|
append,
|
||||||
|
first: 100,
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
import type { AgGridReact } from 'ag-grid-react';
|
import type { AgGridReact } from 'ag-grid-react';
|
||||||
import { useCallback, useMemo, useRef } from 'react';
|
import { useCallback, useRef, useMemo } from 'react';
|
||||||
import { FillsTable } from './fills-table';
|
|
||||||
import { fillsDataProvider } from './fills-data-provider';
|
|
||||||
import { useDataProvider } from '@vegaprotocol/react-helpers';
|
import { useDataProvider } from '@vegaprotocol/react-helpers';
|
||||||
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
|
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
|
||||||
import type { FillsVariables } from './__generated__/Fills';
|
import { FillsTable } from './fills-table';
|
||||||
import type { FillFields } from './__generated__/FillFields';
|
import type { IGetRowsParams } from 'ag-grid-community';
|
||||||
|
|
||||||
|
import { fillsDataProvider as dataProvider } from './fills-data-provider';
|
||||||
|
import type { Fills_party_tradesPaged_edges } from './__generated__/Fills';
|
||||||
import type { FillsSub_trades } from './__generated__/FillsSub';
|
import type { FillsSub_trades } from './__generated__/FillsSub';
|
||||||
import isEqual from 'lodash/isEqual';
|
|
||||||
|
|
||||||
interface FillsManagerProps {
|
interface FillsManagerProps {
|
||||||
partyId: string;
|
partyId: string;
|
||||||
@ -15,66 +15,78 @@ interface FillsManagerProps {
|
|||||||
|
|
||||||
export const FillsManager = ({ partyId }: FillsManagerProps) => {
|
export const FillsManager = ({ partyId }: FillsManagerProps) => {
|
||||||
const gridRef = useRef<AgGridReact | null>(null);
|
const gridRef = useRef<AgGridReact | null>(null);
|
||||||
const variables = useMemo<FillsVariables>(
|
const dataRef = useRef<Fills_party_tradesPaged_edges[] | null>(null);
|
||||||
() => ({
|
const totalCountRef = useRef<number | undefined>(undefined);
|
||||||
partyId,
|
|
||||||
pagination: {
|
|
||||||
last: 300,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
[partyId]
|
|
||||||
);
|
|
||||||
const update = useCallback((delta: FillsSub_trades[]) => {
|
|
||||||
if (!gridRef.current) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const updateRows: FillFields[] = [];
|
|
||||||
const add: FillFields[] = [];
|
|
||||||
|
|
||||||
delta.forEach((d) => {
|
const update = useCallback(
|
||||||
|
({ data }: { data: Fills_party_tradesPaged_edges[] }) => {
|
||||||
if (!gridRef.current?.api) {
|
if (!gridRef.current?.api) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
dataRef.current = data;
|
||||||
const rowNode = gridRef.current.api.getRowNode(d.id);
|
gridRef.current.api.refreshInfiniteCache();
|
||||||
|
return true;
|
||||||
if (rowNode) {
|
},
|
||||||
if (!isEqual(d, rowNode.data)) {
|
[]
|
||||||
updateRows.push(d);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
add.push(d);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (updateRows.length || add.length) {
|
|
||||||
gridRef.current.api.applyTransactionAsync({
|
|
||||||
update: updateRows,
|
|
||||||
add,
|
|
||||||
addIndex: 0,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const { data, loading, error } = useDataProvider(
|
|
||||||
fillsDataProvider,
|
|
||||||
update,
|
|
||||||
variables
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const fills = useMemo(() => {
|
const insert = useCallback(
|
||||||
if (!data?.length) {
|
({
|
||||||
return [];
|
data,
|
||||||
}
|
totalCount,
|
||||||
|
}: {
|
||||||
|
data: Fills_party_tradesPaged_edges[];
|
||||||
|
totalCount?: number;
|
||||||
|
}) => {
|
||||||
|
dataRef.current = data;
|
||||||
|
totalCountRef.current = totalCount;
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
return data;
|
const variables = useMemo(() => ({ partyId }), [partyId]);
|
||||||
}, [data]);
|
|
||||||
|
const { data, error, loading, load, totalCount } = useDataProvider<
|
||||||
|
Fills_party_tradesPaged_edges[],
|
||||||
|
FillsSub_trades[]
|
||||||
|
>({ dataProvider, update, insert, variables });
|
||||||
|
totalCountRef.current = totalCount;
|
||||||
|
dataRef.current = data;
|
||||||
|
|
||||||
|
const getRows = async ({
|
||||||
|
successCallback,
|
||||||
|
failCallback,
|
||||||
|
startRow,
|
||||||
|
endRow,
|
||||||
|
}: IGetRowsParams) => {
|
||||||
|
try {
|
||||||
|
if (dataRef.current && dataRef.current.length < endRow) {
|
||||||
|
await load({
|
||||||
|
first: endRow - startRow,
|
||||||
|
after: dataRef.current[dataRef.current.length - 1].cursor,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const rowsThisBlock = dataRef.current
|
||||||
|
? dataRef.current.slice(startRow, endRow).map((edge) => edge.node)
|
||||||
|
: [];
|
||||||
|
let lastRow = -1;
|
||||||
|
if (totalCountRef.current !== undefined) {
|
||||||
|
if (!totalCountRef.current) {
|
||||||
|
lastRow = 0;
|
||||||
|
} else if (totalCountRef.current <= endRow) {
|
||||||
|
lastRow = totalCountRef.current;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
successCallback(rowsThisBlock, lastRow);
|
||||||
|
} catch (e) {
|
||||||
|
failCallback();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AsyncRenderer data={fills} loading={loading} error={error}>
|
<AsyncRenderer loading={loading} error={error} data={data}>
|
||||||
<FillsTable ref={gridRef} partyId={partyId} fills={fills} />
|
<FillsTable ref={gridRef} partyId={partyId} datasource={{ getRows }} />
|
||||||
</AsyncRenderer>
|
</AsyncRenderer>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,12 +1,25 @@
|
|||||||
import { render, act, screen, waitFor } from '@testing-library/react';
|
import { render, screen, waitFor } from '@testing-library/react';
|
||||||
import { getDateTimeFormat } from '@vegaprotocol/react-helpers';
|
import { getDateTimeFormat } from '@vegaprotocol/react-helpers';
|
||||||
import { Side } from '@vegaprotocol/types';
|
import { Side } from '@vegaprotocol/types';
|
||||||
import type { PartialDeep } from 'type-fest';
|
import type { PartialDeep } from 'type-fest';
|
||||||
|
|
||||||
import { FillsTable } from './fills-table';
|
import { FillsTable } from './fills-table';
|
||||||
import { generateFill } from './test-helpers';
|
import { generateFill, makeGetRows } from './test-helpers';
|
||||||
import type { FillFields } from './__generated__/FillFields';
|
import type { FillFields } from './__generated__/FillFields';
|
||||||
|
|
||||||
|
const waitForGridToBeInTheDOM = () => {
|
||||||
|
return waitFor(() => {
|
||||||
|
expect(document.querySelector('.ag-root-wrapper')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// since our grid starts with no data, when the overlay has gone, data has loaded
|
||||||
|
const waitForDataToHaveLoaded = () => {
|
||||||
|
return waitFor(() => {
|
||||||
|
expect(document.querySelector('.ag-overlay-no-rows-center')).toBeNull();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
describe('FillsTable', () => {
|
describe('FillsTable', () => {
|
||||||
let defaultFill: PartialDeep<FillFields>;
|
let defaultFill: PartialDeep<FillFields>;
|
||||||
|
|
||||||
@ -34,9 +47,14 @@ describe('FillsTable', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('correct columns are rendered', async () => {
|
it('correct columns are rendered', async () => {
|
||||||
await act(async () => {
|
render(
|
||||||
render(<FillsTable partyId="party-id" fills={[generateFill()]} />);
|
<FillsTable
|
||||||
});
|
partyId="party-id"
|
||||||
|
datasource={{ getRows: makeGetRows([generateFill()]) }}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
await waitForGridToBeInTheDOM();
|
||||||
|
await waitForDataToHaveLoaded();
|
||||||
|
|
||||||
const headers = screen.getAllByRole('columnheader');
|
const headers = screen.getAllByRole('columnheader');
|
||||||
expect(headers).toHaveLength(7);
|
expect(headers).toHaveLength(7);
|
||||||
@ -66,14 +84,14 @@ describe('FillsTable', () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const { container } = render(
|
render(
|
||||||
<FillsTable partyId={partyId} fills={[buyerFill]} />
|
<FillsTable
|
||||||
|
partyId={partyId}
|
||||||
|
datasource={{ getRows: makeGetRows([buyerFill]) }}
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
|
await waitForGridToBeInTheDOM();
|
||||||
// Check grid has been rendered
|
await waitForDataToHaveLoaded();
|
||||||
await waitFor(() => {
|
|
||||||
expect(container.querySelector('.ag-root-wrapper')).toBeInTheDocument();
|
|
||||||
});
|
|
||||||
|
|
||||||
const cells = screen.getAllByRole('gridcell');
|
const cells = screen.getAllByRole('gridcell');
|
||||||
const expectedValues = [
|
const expectedValues = [
|
||||||
@ -108,14 +126,14 @@ describe('FillsTable', () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const { container } = render(
|
render(
|
||||||
<FillsTable partyId={partyId} fills={[buyerFill]} />
|
<FillsTable
|
||||||
|
partyId={partyId}
|
||||||
|
datasource={{ getRows: makeGetRows([buyerFill]) }}
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
|
await waitForGridToBeInTheDOM();
|
||||||
// Check grid has been rendered
|
await waitForDataToHaveLoaded();
|
||||||
await waitFor(() => {
|
|
||||||
expect(container.querySelector('.ag-root-wrapper')).toBeInTheDocument();
|
|
||||||
});
|
|
||||||
|
|
||||||
const cells = screen.getAllByRole('gridcell');
|
const cells = screen.getAllByRole('gridcell');
|
||||||
const expectedValues = [
|
const expectedValues = [
|
||||||
@ -144,14 +162,14 @@ describe('FillsTable', () => {
|
|||||||
aggressor: Side.Sell,
|
aggressor: Side.Sell,
|
||||||
});
|
});
|
||||||
|
|
||||||
const { container, rerender } = render(
|
const { rerender } = render(
|
||||||
<FillsTable partyId={partyId} fills={[takerFill]} />
|
<FillsTable
|
||||||
|
partyId={partyId}
|
||||||
|
datasource={{ getRows: makeGetRows([takerFill]) }}
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
|
await waitForGridToBeInTheDOM();
|
||||||
// Check grid has been rendered
|
await waitForDataToHaveLoaded();
|
||||||
await waitFor(() => {
|
|
||||||
expect(container.querySelector('.ag-root-wrapper')).toBeInTheDocument();
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
screen
|
screen
|
||||||
@ -166,7 +184,14 @@ describe('FillsTable', () => {
|
|||||||
aggressor: Side.Buy,
|
aggressor: Side.Buy,
|
||||||
});
|
});
|
||||||
|
|
||||||
rerender(<FillsTable partyId={partyId} fills={[makerFill]} />);
|
rerender(
|
||||||
|
<FillsTable
|
||||||
|
partyId={partyId}
|
||||||
|
datasource={{ getRows: makeGetRows([makerFill]) }}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
await waitForGridToBeInTheDOM();
|
||||||
|
await waitForDataToHaveLoaded();
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
screen
|
screen
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import type { Story, Meta } from '@storybook/react';
|
import type { Story, Meta } from '@storybook/react';
|
||||||
import type { FillsTableProps } from './fills-table';
|
import type { FillsTableProps } from './fills-table';
|
||||||
import { FillsTable } from './fills-table';
|
import { FillsTable } from './fills-table';
|
||||||
import { generateFills } from './test-helpers';
|
import { generateFills, makeGetRows } from './test-helpers';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
component: FillsTable,
|
component: FillsTable,
|
||||||
@ -14,5 +14,9 @@ export const Default = Template.bind({});
|
|||||||
const fills = generateFills();
|
const fills = generateFills();
|
||||||
Default.args = {
|
Default.args = {
|
||||||
partyId: 'party-id',
|
partyId: 'party-id',
|
||||||
fills: fills.party?.tradesPaged.edges.map((e) => e.node),
|
datasource: {
|
||||||
|
getRows: makeGetRows(
|
||||||
|
fills.party?.tradesPaged.edges.map((e) => e.node) || []
|
||||||
|
),
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
@ -10,25 +10,26 @@ import { AgGridColumn } from 'ag-grid-react';
|
|||||||
import { AgGridDynamic as AgGrid } from '@vegaprotocol/ui-toolkit';
|
import { AgGridDynamic as AgGrid } from '@vegaprotocol/ui-toolkit';
|
||||||
import { forwardRef } from 'react';
|
import { forwardRef } from 'react';
|
||||||
import type { FillFields } from './__generated__/FillFields';
|
import type { FillFields } from './__generated__/FillFields';
|
||||||
import type { ValueFormatterParams } from 'ag-grid-community';
|
import type { ValueFormatterParams, IDatasource } from 'ag-grid-community';
|
||||||
import BigNumber from 'bignumber.js';
|
import BigNumber from 'bignumber.js';
|
||||||
import { Side } from '@vegaprotocol/types';
|
import { Side } from '@vegaprotocol/types';
|
||||||
|
|
||||||
export interface FillsTableProps {
|
export interface FillsTableProps {
|
||||||
partyId: string;
|
partyId: string;
|
||||||
fills: FillFields[];
|
datasource: IDatasource;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const FillsTable = forwardRef<AgGridReact, FillsTableProps>(
|
export const FillsTable = forwardRef<AgGridReact, FillsTableProps>(
|
||||||
({ partyId, fills }, ref) => {
|
({ partyId, datasource }, ref) => {
|
||||||
return (
|
return (
|
||||||
<AgGrid
|
<AgGrid
|
||||||
ref={ref}
|
ref={ref}
|
||||||
rowData={fills}
|
|
||||||
overlayNoRowsTemplate={t('No fills')}
|
overlayNoRowsTemplate={t('No fills')}
|
||||||
defaultColDef={{ flex: 1, resizable: true }}
|
defaultColDef={{ flex: 1, resizable: true }}
|
||||||
style={{ width: '100%', height: '100%' }}
|
style={{ width: '100%', height: '100%' }}
|
||||||
getRowId={({ data }) => data.id}
|
getRowId={({ data }) => data?.id}
|
||||||
|
rowModelType="infinite"
|
||||||
|
datasource={datasource}
|
||||||
>
|
>
|
||||||
<AgGridColumn headerName={t('Market')} field="market.name" />
|
<AgGridColumn headerName={t('Market')} field="market.name" />
|
||||||
<AgGridColumn
|
<AgGridColumn
|
||||||
@ -36,9 +37,9 @@ export const FillsTable = forwardRef<AgGridReact, FillsTableProps>(
|
|||||||
field="size"
|
field="size"
|
||||||
cellClass={({ data }: { data: FillFields }) => {
|
cellClass={({ data }: { data: FillFields }) => {
|
||||||
let className = '';
|
let className = '';
|
||||||
if (data.buyer.id === partyId) {
|
if (data?.buyer.id === partyId) {
|
||||||
className = 'text-vega-green';
|
className = 'text-vega-green';
|
||||||
} else if (data.seller.id) {
|
} else if (data?.seller.id) {
|
||||||
className = 'text-vega-red';
|
className = 'text-vega-red';
|
||||||
}
|
}
|
||||||
return className;
|
return className;
|
||||||
@ -69,6 +70,9 @@ export const FillsTable = forwardRef<AgGridReact, FillsTableProps>(
|
|||||||
headerName={t('Date')}
|
headerName={t('Date')}
|
||||||
field="createdAt"
|
field="createdAt"
|
||||||
valueFormatter={({ value }: ValueFormatterParams) => {
|
valueFormatter={({ value }: ValueFormatterParams) => {
|
||||||
|
if (value === undefined) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
return getDateTimeFormat().format(new Date(value));
|
return getDateTimeFormat().format(new Date(value));
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
@ -78,56 +82,68 @@ export const FillsTable = forwardRef<AgGridReact, FillsTableProps>(
|
|||||||
);
|
);
|
||||||
|
|
||||||
const formatPrice = ({ value, data }: ValueFormatterParams) => {
|
const formatPrice = ({ value, data }: ValueFormatterParams) => {
|
||||||
|
if (value === undefined) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
const asset =
|
const asset =
|
||||||
data.market.tradableInstrument.instrument.product.settlementAsset.symbol;
|
data?.market.tradableInstrument.instrument.product.settlementAsset.symbol;
|
||||||
const valueFormatted = addDecimalsFormatNumber(
|
const valueFormatted = addDecimalsFormatNumber(
|
||||||
value,
|
value,
|
||||||
data.market.decimalPlaces
|
data?.market.decimalPlaces
|
||||||
);
|
);
|
||||||
return `${valueFormatted} ${asset}`;
|
return `${valueFormatted} ${asset}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
const formatSize = (partyId: string) => {
|
const formatSize = (partyId: string) => {
|
||||||
return ({ value, data }: ValueFormatterParams) => {
|
return ({ value, data }: ValueFormatterParams) => {
|
||||||
|
if (value === undefined) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
let prefix;
|
let prefix;
|
||||||
if (data.buyer.id === partyId) {
|
if (data?.buyer.id === partyId) {
|
||||||
prefix = '+';
|
prefix = '+';
|
||||||
} else if (data.seller.id) {
|
} else if (data?.seller.id) {
|
||||||
prefix = '-';
|
prefix = '-';
|
||||||
}
|
}
|
||||||
|
|
||||||
const size = addDecimalsFormatNumber(
|
const size = addDecimalsFormatNumber(
|
||||||
value,
|
value,
|
||||||
data.market.positionDecimalPlaces
|
data?.market.positionDecimalPlaces
|
||||||
);
|
);
|
||||||
return `${prefix}${size}`;
|
return `${prefix}${size}`;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const formatTotal = ({ value, data }: ValueFormatterParams) => {
|
const formatTotal = ({ value, data }: ValueFormatterParams) => {
|
||||||
|
if (value === undefined) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
const asset =
|
const asset =
|
||||||
data.market.tradableInstrument.instrument.product.settlementAsset.symbol;
|
data?.market.tradableInstrument.instrument.product.settlementAsset.symbol;
|
||||||
const size = new BigNumber(
|
const size = new BigNumber(
|
||||||
addDecimal(data.size, data.market.positionDecimalPlaces)
|
addDecimal(data?.size, data?.market.positionDecimalPlaces)
|
||||||
);
|
);
|
||||||
const price = new BigNumber(addDecimal(value, data.market.decimalPlaces));
|
const price = new BigNumber(addDecimal(value, data?.market.decimalPlaces));
|
||||||
|
|
||||||
const total = size.times(price).toString();
|
const total = size.times(price).toString();
|
||||||
const valueFormatted = formatNumber(total, data.market.decimalPlaces);
|
const valueFormatted = formatNumber(total, data?.market.decimalPlaces);
|
||||||
return `${valueFormatted} ${asset}`;
|
return `${valueFormatted} ${asset}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
const formatRole = (partyId: string) => {
|
const formatRole = (partyId: string) => {
|
||||||
return ({ value, data }: ValueFormatterParams) => {
|
return ({ value, data }: ValueFormatterParams) => {
|
||||||
|
if (value === undefined) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
const taker = t('Taker');
|
const taker = t('Taker');
|
||||||
const maker = t('Maker');
|
const maker = t('Maker');
|
||||||
if (data.buyer.id === partyId) {
|
if (data?.buyer.id === partyId) {
|
||||||
if (value === Side.Buy) {
|
if (value === Side.Buy) {
|
||||||
return taker;
|
return taker;
|
||||||
} else {
|
} else {
|
||||||
return maker;
|
return maker;
|
||||||
}
|
}
|
||||||
} else if (data.seller.id === partyId) {
|
} else if (data?.seller.id === partyId) {
|
||||||
if (value === Side.Sell) {
|
if (value === Side.Sell) {
|
||||||
return taker;
|
return taker;
|
||||||
} else {
|
} else {
|
||||||
@ -141,12 +157,15 @@ const formatRole = (partyId: string) => {
|
|||||||
|
|
||||||
const formatFee = (partyId: string) => {
|
const formatFee = (partyId: string) => {
|
||||||
return ({ value, data }: ValueFormatterParams) => {
|
return ({ value, data }: ValueFormatterParams) => {
|
||||||
|
if (value === undefined) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
const asset = value.settlementAsset;
|
const asset = value.settlementAsset;
|
||||||
let feesObj;
|
let feesObj;
|
||||||
if (data.buyer.id === partyId) {
|
if (data?.buyer.id === partyId) {
|
||||||
feesObj = data.buyerFee;
|
feesObj = data?.buyerFee;
|
||||||
} else if (data.seller.id === partyId) {
|
} else if (data?.seller.id === partyId) {
|
||||||
feesObj = data.sellerFee;
|
feesObj = data?.sellerFee;
|
||||||
} else {
|
} else {
|
||||||
return '-';
|
return '-';
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { Side } from '@vegaprotocol/types';
|
import { Side } from '@vegaprotocol/types';
|
||||||
import merge from 'lodash/merge';
|
import merge from 'lodash/merge';
|
||||||
|
import type { IGetRowsParams } from 'ag-grid-community';
|
||||||
import type { PartialDeep } from 'type-fest';
|
import type { PartialDeep } from 'type-fest';
|
||||||
import type {
|
import type {
|
||||||
Fills,
|
Fills,
|
||||||
@ -132,3 +133,9 @@ export const generateFill = (
|
|||||||
|
|
||||||
return merge(defaultFill, override);
|
return merge(defaultFill, override);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const makeGetRows =
|
||||||
|
(data: Fills_party_tradesPaged_edges_node[]) =>
|
||||||
|
({ successCallback }: IGetRowsParams) => {
|
||||||
|
successCallback(data, data.length);
|
||||||
|
};
|
||||||
|
@ -6,7 +6,7 @@ import {
|
|||||||
addDecimal,
|
addDecimal,
|
||||||
ThemeContext,
|
ThemeContext,
|
||||||
} from '@vegaprotocol/react-helpers';
|
} from '@vegaprotocol/react-helpers';
|
||||||
import { marketDepthDataProvider } from './market-depth-data-provider';
|
import dataProvider from './market-depth-data-provider';
|
||||||
import {
|
import {
|
||||||
useCallback,
|
useCallback,
|
||||||
useEffect,
|
useEffect,
|
||||||
@ -87,7 +87,7 @@ export const DepthChartContainer = ({ marketId }: DepthChartManagerProps) => {
|
|||||||
|
|
||||||
// Apply updates to the table
|
// Apply updates to the table
|
||||||
const update = useCallback(
|
const update = useCallback(
|
||||||
(delta: MarketDepthSubscription_marketDepthUpdate) => {
|
({ delta }: { delta: MarketDepthSubscription_marketDepthUpdate }) => {
|
||||||
if (!dataRef.current) {
|
if (!dataRef.current) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -122,11 +122,11 @@ export const DepthChartContainer = ({ marketId }: DepthChartManagerProps) => {
|
|||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
|
|
||||||
const { data, error, loading } = useDataProvider(
|
const { data, error, loading } = useDataProvider({
|
||||||
marketDepthDataProvider,
|
dataProvider,
|
||||||
update,
|
update,
|
||||||
variables
|
variables,
|
||||||
);
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!data) {
|
if (!data) {
|
||||||
|
@ -131,3 +131,5 @@ export const marketDepthDataProvider = makeDataProvider(
|
|||||||
getData,
|
getData,
|
||||||
getDelta
|
getDelta
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export default marketDepthDataProvider;
|
||||||
|
@ -150,9 +150,9 @@ export const compactRows = (
|
|||||||
groupedByLevel[price].pop() as PartialOrderbookRowData
|
groupedByLevel[price].pop() as PartialOrderbookRowData
|
||||||
);
|
);
|
||||||
row.price = price;
|
row.price = price;
|
||||||
let subRow: PartialOrderbookRowData | undefined;
|
let subRow: PartialOrderbookRowData | undefined =
|
||||||
// eslint-disable-next-line no-cond-assign
|
groupedByLevel[price].pop();
|
||||||
while ((subRow = groupedByLevel[price].pop())) {
|
while (subRow) {
|
||||||
row.ask += subRow.ask;
|
row.ask += subRow.ask;
|
||||||
row.bid += subRow.bid;
|
row.bid += subRow.bid;
|
||||||
if (subRow.ask) {
|
if (subRow.ask) {
|
||||||
@ -161,6 +161,7 @@ export const compactRows = (
|
|||||||
if (subRow.bid) {
|
if (subRow.bid) {
|
||||||
row.bidByLevel[subRow.price] = subRow.bid;
|
row.bidByLevel[subRow.price] = subRow.bid;
|
||||||
}
|
}
|
||||||
|
subRow = groupedByLevel[price].pop();
|
||||||
}
|
}
|
||||||
orderbookData.push(row);
|
orderbookData.push(row);
|
||||||
});
|
});
|
||||||
|
@ -2,7 +2,7 @@ import throttle from 'lodash/throttle';
|
|||||||
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
|
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
|
||||||
import { Orderbook } from './orderbook';
|
import { Orderbook } from './orderbook';
|
||||||
import { useDataProvider } from '@vegaprotocol/react-helpers';
|
import { useDataProvider } from '@vegaprotocol/react-helpers';
|
||||||
import { marketDepthDataProvider } from './market-depth-data-provider';
|
import dataProvider from './market-depth-data-provider';
|
||||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
import type { MarketDepthSubscription_marketDepthUpdate } from './__generated__/MarketDepthSubscription';
|
import type { MarketDepthSubscription_marketDepthUpdate } from './__generated__/MarketDepthSubscription';
|
||||||
import {
|
import {
|
||||||
@ -46,7 +46,7 @@ export const OrderbookManager = ({ marketId }: OrderbookManagerProps) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const update = useCallback(
|
const update = useCallback(
|
||||||
(delta: MarketDepthSubscription_marketDepthUpdate) => {
|
({ delta }: { delta: MarketDepthSubscription_marketDepthUpdate }) => {
|
||||||
if (!dataRef.current.rows) {
|
if (!dataRef.current.rows) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -76,11 +76,11 @@ export const OrderbookManager = ({ marketId }: OrderbookManagerProps) => {
|
|||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
|
|
||||||
const { data, error, loading, flush } = useDataProvider(
|
const { data, error, loading, flush } = useDataProvider({
|
||||||
marketDepthDataProvider,
|
dataProvider,
|
||||||
update,
|
update,
|
||||||
variables
|
variables,
|
||||||
);
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!data) {
|
if (!data) {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { forwardRef } from 'react';
|
import { forwardRef } from 'react';
|
||||||
import type { ValueFormatterParams } from 'ag-grid-community';
|
import type { IDatasource, ValueFormatterParams } from 'ag-grid-community';
|
||||||
import {
|
import {
|
||||||
PriceFlashCell,
|
PriceFlashCell,
|
||||||
addDecimalsFormatNumber,
|
addDecimalsFormatNumber,
|
||||||
@ -8,30 +8,22 @@ import {
|
|||||||
import { AgGridDynamic as AgGrid } from '@vegaprotocol/ui-toolkit';
|
import { AgGridDynamic as AgGrid } from '@vegaprotocol/ui-toolkit';
|
||||||
import { AgGridColumn } from 'ag-grid-react';
|
import { AgGridColumn } from 'ag-grid-react';
|
||||||
import type { AgGridReact } from 'ag-grid-react';
|
import type { AgGridReact } from 'ag-grid-react';
|
||||||
import type {
|
import type { Markets_markets } from '../__generated__/Markets';
|
||||||
Markets_markets,
|
|
||||||
Markets_markets_data_market,
|
|
||||||
} from '../__generated__/Markets';
|
|
||||||
|
|
||||||
interface MarketListTableProps {
|
interface MarketListTableProps {
|
||||||
data: Markets_markets[] | null;
|
datasource: IDatasource;
|
||||||
onRowClicked: (marketId: string) => void;
|
onRowClicked: (marketId: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getRowId = ({
|
|
||||||
data,
|
|
||||||
}: {
|
|
||||||
data: Markets_markets | Markets_markets_data_market;
|
|
||||||
}) => data.id;
|
|
||||||
|
|
||||||
export const MarketListTable = forwardRef<AgGridReact, MarketListTableProps>(
|
export const MarketListTable = forwardRef<AgGridReact, MarketListTableProps>(
|
||||||
({ data, onRowClicked }, ref) => {
|
({ datasource, onRowClicked }, ref) => {
|
||||||
return (
|
return (
|
||||||
<AgGrid
|
<AgGrid
|
||||||
style={{ width: '100%', height: '100%' }}
|
style={{ width: '100%', height: '100%' }}
|
||||||
overlayNoRowsTemplate={t('No markets')}
|
overlayNoRowsTemplate={t('No markets')}
|
||||||
rowData={data}
|
rowModelType="infinite"
|
||||||
getRowId={getRowId}
|
datasource={datasource}
|
||||||
|
getRowId={({ data }) => data?.id}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
defaultColDef={{
|
defaultColDef={{
|
||||||
flex: 1,
|
flex: 1,
|
||||||
@ -55,7 +47,9 @@ export const MarketListTable = forwardRef<AgGridReact, MarketListTableProps>(
|
|||||||
headerName={t('State')}
|
headerName={t('State')}
|
||||||
field="data"
|
field="data"
|
||||||
valueFormatter={({ value }: ValueFormatterParams) =>
|
valueFormatter={({ value }: ValueFormatterParams) =>
|
||||||
`${value.market.state} (${value.market.tradingMode})`
|
value === undefined
|
||||||
|
? value
|
||||||
|
: `${value.market.state} (${value.market.tradingMode})`
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<AgGridColumn
|
<AgGridColumn
|
||||||
@ -64,7 +58,9 @@ export const MarketListTable = forwardRef<AgGridReact, MarketListTableProps>(
|
|||||||
type="rightAligned"
|
type="rightAligned"
|
||||||
cellRenderer="PriceFlashCell"
|
cellRenderer="PriceFlashCell"
|
||||||
valueFormatter={({ value, data }: ValueFormatterParams) =>
|
valueFormatter={({ value, data }: ValueFormatterParams) =>
|
||||||
addDecimalsFormatNumber(value, data.decimalPlaces)
|
value === undefined
|
||||||
|
? value
|
||||||
|
: addDecimalsFormatNumber(value, data.decimalPlaces)
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<AgGridColumn
|
<AgGridColumn
|
||||||
@ -72,7 +68,9 @@ export const MarketListTable = forwardRef<AgGridReact, MarketListTableProps>(
|
|||||||
field="data.bestOfferPrice"
|
field="data.bestOfferPrice"
|
||||||
type="rightAligned"
|
type="rightAligned"
|
||||||
valueFormatter={({ value, data }: ValueFormatterParams) =>
|
valueFormatter={({ value, data }: ValueFormatterParams) =>
|
||||||
addDecimalsFormatNumber(value, data.decimalPlaces)
|
value === undefined
|
||||||
|
? value
|
||||||
|
: addDecimalsFormatNumber(value, data.decimalPlaces)
|
||||||
}
|
}
|
||||||
cellRenderer="PriceFlashCell"
|
cellRenderer="PriceFlashCell"
|
||||||
/>
|
/>
|
||||||
@ -82,7 +80,9 @@ export const MarketListTable = forwardRef<AgGridReact, MarketListTableProps>(
|
|||||||
type="rightAligned"
|
type="rightAligned"
|
||||||
cellRenderer="PriceFlashCell"
|
cellRenderer="PriceFlashCell"
|
||||||
valueFormatter={({ value, data }: ValueFormatterParams) =>
|
valueFormatter={({ value, data }: ValueFormatterParams) =>
|
||||||
addDecimalsFormatNumber(value, data.decimalPlaces)
|
value === undefined
|
||||||
|
? value
|
||||||
|
: addDecimalsFormatNumber(value, data.decimalPlaces)
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<AgGridColumn headerName={t('Description')} field="name" />
|
<AgGridColumn headerName={t('Description')} field="name" />
|
||||||
|
@ -1,61 +1,51 @@
|
|||||||
import { useRef, useCallback } from 'react';
|
import { useRef, useCallback } from 'react';
|
||||||
import { produce } from 'immer';
|
|
||||||
import merge from 'lodash/merge';
|
|
||||||
import { useRouter } from 'next/router';
|
import { useRouter } from 'next/router';
|
||||||
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
|
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
|
||||||
import { MarketListTable, getRowId } from './market-list-table';
|
import { MarketListTable } from './market-list-table';
|
||||||
import { useDataProvider } from '@vegaprotocol/react-helpers';
|
import { useDataProvider } from '@vegaprotocol/react-helpers';
|
||||||
import type { AgGridReact } from 'ag-grid-react';
|
import type { AgGridReact } from 'ag-grid-react';
|
||||||
|
import type { IGetRowsParams } from 'ag-grid-community';
|
||||||
import type {
|
import type {
|
||||||
Markets_markets,
|
Markets_markets,
|
||||||
Markets_markets_data,
|
Markets_markets_data,
|
||||||
} from '../../components/__generated__/Markets';
|
} from '../../components/__generated__/Markets';
|
||||||
import { marketsDataProvider } from './markets-data-provider';
|
import { marketsDataProvider as dataProvider } from './markets-data-provider';
|
||||||
|
|
||||||
export const MarketsContainer = () => {
|
export const MarketsContainer = () => {
|
||||||
const { push } = useRouter();
|
const { push } = useRouter();
|
||||||
const gridRef = useRef<AgGridReact | null>(null);
|
const gridRef = useRef<AgGridReact | null>(null);
|
||||||
const update = useCallback(
|
const dataRef = useRef<Markets_markets[] | null>(null);
|
||||||
(delta: Markets_markets_data) => {
|
const update = useCallback(({ data }: { data: Markets_markets[] }) => {
|
||||||
const update: Markets_markets[] = [];
|
if (!gridRef.current?.api) {
|
||||||
const add: Markets_markets[] = [];
|
return false;
|
||||||
if (!gridRef.current?.api) {
|
}
|
||||||
return false;
|
dataRef.current = data;
|
||||||
}
|
gridRef.current.api.refreshInfiniteCache();
|
||||||
const rowNode = gridRef.current.api.getRowNode(
|
return true;
|
||||||
getRowId({ data: delta.market })
|
}, []);
|
||||||
);
|
|
||||||
if (rowNode) {
|
|
||||||
const updatedData = produce<Markets_markets_data>(
|
|
||||||
rowNode.data.data,
|
|
||||||
(draft: Markets_markets_data) => merge(draft, delta)
|
|
||||||
);
|
|
||||||
if (updatedData !== rowNode.data.data) {
|
|
||||||
update.push({ ...rowNode.data, data: updatedData });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// @TODO - else add new market
|
|
||||||
if (update.length || add.length) {
|
|
||||||
gridRef.current.api.applyTransactionAsync({
|
|
||||||
update,
|
|
||||||
add,
|
|
||||||
addIndex: 0,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
[gridRef]
|
|
||||||
);
|
|
||||||
const { data, error, loading } = useDataProvider<
|
const { data, error, loading } = useDataProvider<
|
||||||
Markets_markets[],
|
Markets_markets[],
|
||||||
Markets_markets_data
|
Markets_markets_data
|
||||||
>(marketsDataProvider, update);
|
>({ dataProvider, update });
|
||||||
|
dataRef.current = data;
|
||||||
|
|
||||||
|
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);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AsyncRenderer loading={loading} error={error} data={data}>
|
<AsyncRenderer loading={loading} error={error} data={data}>
|
||||||
<MarketListTable
|
<MarketListTable
|
||||||
|
datasource={{ getRows }}
|
||||||
ref={gridRef}
|
ref={gridRef}
|
||||||
data={data}
|
|
||||||
onRowClicked={(id) => push(`/markets/${id}`)}
|
onRowClicked={(id) => push(`/markets/${id}`)}
|
||||||
/>
|
/>
|
||||||
</AsyncRenderer>
|
</AsyncRenderer>
|
||||||
|
@ -91,14 +91,16 @@ const MARKET_DATA_SUB = gql`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const update = (data: Markets_markets[], delta: MarketDataSub_marketData) =>
|
const update = (data: Markets_markets[], delta: MarketDataSub_marketData) => {
|
||||||
produce(data, (draft) => {
|
return produce(data, (draft) => {
|
||||||
const index = draft.findIndex((m) => m.id === delta.market.id);
|
const index = draft.findIndex((m) => m.id === delta.market.id);
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
draft[index].data = delta;
|
draft[index].data = delta;
|
||||||
}
|
}
|
||||||
// @TODO - else push new market to draft
|
// @TODO - else push new market to draft
|
||||||
});
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const getData = (responseData: Markets): Markets_markets[] | null =>
|
const getData = (responseData: Markets): Markets_markets[] | null =>
|
||||||
responseData.markets;
|
responseData.markets;
|
||||||
const getDelta = (subscriptionData: MarketDataSub): MarketDataSub_marketData =>
|
const getDelta = (subscriptionData: MarketDataSub): MarketDataSub_marketData =>
|
||||||
|
@ -79,8 +79,8 @@ export const prepareIncomingOrders = (delta: OrderFields[]) => {
|
|||||||
return incoming;
|
return incoming;
|
||||||
};
|
};
|
||||||
|
|
||||||
const update = (data: OrderFields[], delta: OrderFields[]) =>
|
const update = (data: OrderFields[], delta: OrderFields[]) => {
|
||||||
produce(data, (draft) => {
|
return produce(data, (draft) => {
|
||||||
const incoming = prepareIncomingOrders(delta);
|
const incoming = prepareIncomingOrders(delta);
|
||||||
|
|
||||||
// Add or update incoming orders
|
// Add or update incoming orders
|
||||||
@ -93,6 +93,7 @@ const update = (data: OrderFields[], delta: OrderFields[]) =>
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const getData = (responseData: Orders): Orders_party_orders[] | null =>
|
const getData = (responseData: Orders): Orders_party_orders[] | null =>
|
||||||
responseData?.party?.orders || null;
|
responseData?.party?.orders || null;
|
||||||
|
@ -3,7 +3,7 @@ import { OrderList } from '../order-list';
|
|||||||
import type { OrderFields } from '../__generated__/OrderFields';
|
import type { OrderFields } from '../__generated__/OrderFields';
|
||||||
import { useDataProvider } from '@vegaprotocol/react-helpers';
|
import { useDataProvider } from '@vegaprotocol/react-helpers';
|
||||||
import {
|
import {
|
||||||
ordersDataProvider,
|
ordersDataProvider as dataProvider,
|
||||||
prepareIncomingOrders,
|
prepareIncomingOrders,
|
||||||
sortOrders,
|
sortOrders,
|
||||||
} from '../order-data-provider';
|
} from '../order-data-provider';
|
||||||
@ -21,7 +21,7 @@ export const OrderListManager = ({ partyId }: OrderListManagerProps) => {
|
|||||||
const variables = useMemo(() => ({ partyId }), [partyId]);
|
const variables = useMemo(() => ({ partyId }), [partyId]);
|
||||||
|
|
||||||
// Apply updates to the table
|
// Apply updates to the table
|
||||||
const update = useCallback((delta: OrderSub_orders[]) => {
|
const update = useCallback(({ delta }: { delta: OrderSub_orders[] }) => {
|
||||||
if (!gridRef.current) {
|
if (!gridRef.current) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -57,11 +57,11 @@ export const OrderListManager = ({ partyId }: OrderListManagerProps) => {
|
|||||||
return true;
|
return true;
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const { data, error, loading } = useDataProvider(
|
const { data, error, loading } = useDataProvider({
|
||||||
ordersDataProvider,
|
dataProvider,
|
||||||
update,
|
update,
|
||||||
variables
|
variables,
|
||||||
);
|
});
|
||||||
|
|
||||||
const orders = useMemo(() => {
|
const orders = useMemo(() => {
|
||||||
if (!data) {
|
if (!data) {
|
||||||
|
@ -78,8 +78,8 @@ export const POSITIONS_SUB = gql`
|
|||||||
const update = (
|
const update = (
|
||||||
data: Positions_party_positions[],
|
data: Positions_party_positions[],
|
||||||
delta: PositionSubscribe_positions
|
delta: PositionSubscribe_positions
|
||||||
) =>
|
) => {
|
||||||
produce(data, (draft) => {
|
return produce(data, (draft) => {
|
||||||
const index = draft.findIndex((m) => m.market.id === delta.market.id);
|
const index = draft.findIndex((m) => m.market.id === delta.market.id);
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
draft[index] = delta;
|
draft[index] = delta;
|
||||||
@ -87,6 +87,8 @@ const update = (
|
|||||||
draft.push(delta);
|
draft.push(delta);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const getData = (responseData: Positions): Positions_party_positions[] | null =>
|
const getData = (responseData: Positions): Positions_party_positions[] | null =>
|
||||||
responseData.party ? responseData.party.positions : null;
|
responseData.party ? responseData.party.positions : null;
|
||||||
const getDelta = (
|
const getDelta = (
|
||||||
|
@ -18,7 +18,7 @@ export const PositionsManager = ({ partyId }: PositionsManagerProps) => {
|
|||||||
const gridRef = useRef<AgGridReact | null>(null);
|
const gridRef = useRef<AgGridReact | null>(null);
|
||||||
const variables = useMemo(() => ({ partyId }), [partyId]);
|
const variables = useMemo(() => ({ partyId }), [partyId]);
|
||||||
const update = useCallback(
|
const update = useCallback(
|
||||||
(delta: PositionSubscribe_positions) => {
|
({ delta }: { delta: PositionSubscribe_positions }) => {
|
||||||
const update: Positions_party_positions[] = [];
|
const update: Positions_party_positions[] = [];
|
||||||
const add: Positions_party_positions[] = [];
|
const add: Positions_party_positions[] = [];
|
||||||
if (!gridRef.current?.api) {
|
if (!gridRef.current?.api) {
|
||||||
@ -52,7 +52,7 @@ export const PositionsManager = ({ partyId }: PositionsManagerProps) => {
|
|||||||
const { data, error, loading } = useDataProvider<
|
const { data, error, loading } = useDataProvider<
|
||||||
Positions_party_positions[],
|
Positions_party_positions[],
|
||||||
PositionSubscribe_positions
|
PositionSubscribe_positions
|
||||||
>(positionsDataProvider, update, variables);
|
>({ dataProvider: positionsDataProvider, update, variables });
|
||||||
return (
|
return (
|
||||||
<AsyncRenderer loading={loading} error={error} data={data}>
|
<AsyncRenderer loading={loading} error={error} data={data}>
|
||||||
<PositionsTable ref={gridRef} data={data} />
|
<PositionsTable ref={gridRef} data={data} />
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { useState, useEffect, useRef, useCallback } from 'react';
|
import { useState, useEffect, useRef, useCallback } from 'react';
|
||||||
import { useApolloClient } from '@apollo/client';
|
import { useApolloClient } from '@apollo/client';
|
||||||
import type { OperationVariables } from '@apollo/client';
|
import type { OperationVariables } from '@apollo/client';
|
||||||
import type { Subscribe } from '../lib/generic-data-provider';
|
import type { Subscribe, Pagination, Load } from '../lib/generic-data-provider';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -10,17 +10,33 @@ import type { Subscribe } from '../lib/generic-data-provider';
|
|||||||
* @param variables optional
|
* @param variables optional
|
||||||
* @returns state: data, loading, error, methods: flush (pass updated data to update function without delta), restart: () => void}};
|
* @returns state: data, loading, error, methods: flush (pass updated data to update function without delta), restart: () => void}};
|
||||||
*/
|
*/
|
||||||
export function useDataProvider<Data, Delta>(
|
export function useDataProvider<Data, Delta>({
|
||||||
dataProvider: Subscribe<Data, Delta>,
|
dataProvider,
|
||||||
update?: (delta: Delta) => boolean,
|
update,
|
||||||
variables?: OperationVariables
|
insert,
|
||||||
) {
|
variables,
|
||||||
|
}: {
|
||||||
|
dataProvider: Subscribe<Data, Delta>;
|
||||||
|
update?: ({ delta, data }: { delta: Delta; data: Data }) => boolean;
|
||||||
|
insert?: ({
|
||||||
|
insertionData,
|
||||||
|
data,
|
||||||
|
totalCount,
|
||||||
|
}: {
|
||||||
|
insertionData: Data;
|
||||||
|
data: Data;
|
||||||
|
totalCount?: number;
|
||||||
|
}) => boolean;
|
||||||
|
variables?: OperationVariables;
|
||||||
|
}) {
|
||||||
const client = useApolloClient();
|
const client = useApolloClient();
|
||||||
const [data, setData] = useState<Data | null>(null);
|
const [data, setData] = useState<Data | null>(null);
|
||||||
|
const [totalCount, setTotalCount] = useState<number>();
|
||||||
const [loading, setLoading] = useState<boolean>(true);
|
const [loading, setLoading] = useState<boolean>(true);
|
||||||
const [error, setError] = useState<Error | undefined>(undefined);
|
const [error, setError] = useState<Error | undefined>(undefined);
|
||||||
const flushRef = useRef<(() => void) | undefined>(undefined);
|
const flushRef = useRef<(() => void) | undefined>(undefined);
|
||||||
const reloadRef = useRef<((force?: boolean) => void) | undefined>(undefined);
|
const reloadRef = useRef<((force?: boolean) => void) | undefined>(undefined);
|
||||||
|
const loadRef = useRef<Load<Data> | undefined>(undefined);
|
||||||
const initialized = useRef<boolean>(false);
|
const initialized = useRef<boolean>(false);
|
||||||
const flush = useCallback(() => {
|
const flush = useCallback(() => {
|
||||||
if (flushRef.current) {
|
if (flushRef.current) {
|
||||||
@ -32,30 +48,48 @@ export function useDataProvider<Data, Delta>(
|
|||||||
reloadRef.current(force);
|
reloadRef.current(force);
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
const load = useCallback((pagination: Pagination) => {
|
||||||
|
if (loadRef.current) {
|
||||||
|
return loadRef.current(pagination);
|
||||||
|
}
|
||||||
|
return Promise.reject();
|
||||||
|
}, []);
|
||||||
const callback = useCallback(
|
const callback = useCallback(
|
||||||
({ data, error, loading, delta }) => {
|
({ data, error, loading, delta, insertionData, totalCount }) => {
|
||||||
setError(error);
|
setError(error);
|
||||||
setLoading(loading);
|
setLoading(loading);
|
||||||
if (!error && !loading) {
|
if (!error && !loading) {
|
||||||
// if update function returns true it means that component handles updates
|
// if update or insert function returns true it means that component handles updates
|
||||||
// component can use flush() which will call callback without delta and cause data state update
|
// component can use flush() which will call callback without delta and cause data state update
|
||||||
if (!initialized.current || !delta || !update || !update(delta)) {
|
if (initialized.current) {
|
||||||
initialized.current = true;
|
if (delta && update && update({ delta, data })) {
|
||||||
setData(data);
|
return;
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
insertionData &&
|
||||||
|
insert &&
|
||||||
|
insert({ insertionData, data, totalCount })
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
initialized.current = true;
|
||||||
|
setTotalCount(totalCount);
|
||||||
|
setData(data);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[update]
|
[update, insert]
|
||||||
);
|
);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const { unsubscribe, flush, reload } = dataProvider(
|
const { unsubscribe, flush, reload, load } = dataProvider(
|
||||||
callback,
|
callback,
|
||||||
client,
|
client,
|
||||||
variables
|
variables
|
||||||
);
|
);
|
||||||
flushRef.current = flush;
|
flushRef.current = flush;
|
||||||
reloadRef.current = reload;
|
reloadRef.current = reload;
|
||||||
|
loadRef.current = load;
|
||||||
return unsubscribe;
|
return unsubscribe;
|
||||||
}, [client, initialized, dataProvider, callback, variables]);
|
}, [client, initialized, dataProvider, callback, variables]);
|
||||||
return { data, loading, error, flush, reload };
|
return { data, loading, error, flush, reload, load, totalCount };
|
||||||
}
|
}
|
||||||
|
@ -13,9 +13,30 @@ export interface UpdateCallback<Data, Delta> {
|
|||||||
data: Data | null;
|
data: Data | null;
|
||||||
error?: Error;
|
error?: Error;
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
|
pageInfo: PageInfo | null;
|
||||||
delta?: Delta;
|
delta?: Delta;
|
||||||
|
insertionData?: Data | null;
|
||||||
|
totalCount?: number;
|
||||||
}): void;
|
}): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface Load<Data> {
|
||||||
|
(pagination: Pagination): Promise<Data | null>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Pagination {
|
||||||
|
first?: number;
|
||||||
|
after?: string;
|
||||||
|
last?: number;
|
||||||
|
before?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PageInfo {
|
||||||
|
startCursor?: string;
|
||||||
|
endCursor?: string;
|
||||||
|
hasNextPage?: boolean;
|
||||||
|
hasPreviousPage?: boolean;
|
||||||
|
}
|
||||||
export interface Subscribe<Data, Delta> {
|
export interface Subscribe<Data, Delta> {
|
||||||
(
|
(
|
||||||
callback: UpdateCallback<Data, Delta>,
|
callback: UpdateCallback<Data, Delta>,
|
||||||
@ -25,6 +46,7 @@ export interface Subscribe<Data, Delta> {
|
|||||||
unsubscribe: () => void;
|
unsubscribe: () => void;
|
||||||
reload: (forceReset?: boolean) => void;
|
reload: (forceReset?: boolean) => void;
|
||||||
flush: () => void;
|
flush: () => void;
|
||||||
|
load: Load<Data>;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,8 +57,29 @@ export interface Update<Data, Delta> {
|
|||||||
(data: Data, delta: Delta, reload: (forceReset?: boolean) => void): Data;
|
(data: Data, delta: Delta, reload: (forceReset?: boolean) => void): Data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface Append<Data> {
|
||||||
|
(
|
||||||
|
data: Data | null,
|
||||||
|
pageInfo: PageInfo,
|
||||||
|
insertionData: Data | null,
|
||||||
|
insertionPageInfo: PageInfo | null,
|
||||||
|
pagination?: Pagination
|
||||||
|
): {
|
||||||
|
data: Data | null;
|
||||||
|
pageInfo: PageInfo;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
interface GetData<QueryData, Data> {
|
interface GetData<QueryData, Data> {
|
||||||
(subscriptionData: QueryData): Data | null;
|
(queryData: QueryData): Data | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface GetPageInfo<QueryData> {
|
||||||
|
(queryData: QueryData): PageInfo | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface GetTotalCount<QueryData> {
|
||||||
|
(queryData: QueryData): number | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface GetDelta<SubscriptionData, Delta> {
|
interface GetDelta<SubscriptionData, Delta> {
|
||||||
@ -57,6 +100,12 @@ function makeDataProviderInternal<QueryData, Data, SubscriptionData, Delta>(
|
|||||||
update: Update<Data, Delta>,
|
update: Update<Data, Delta>,
|
||||||
getData: GetData<QueryData, Data>,
|
getData: GetData<QueryData, Data>,
|
||||||
getDelta: GetDelta<SubscriptionData, Delta>,
|
getDelta: GetDelta<SubscriptionData, Delta>,
|
||||||
|
pagination?: {
|
||||||
|
getPageInfo: GetPageInfo<QueryData>;
|
||||||
|
getTotalCount: GetTotalCount<QueryData>;
|
||||||
|
append: Append<Data>;
|
||||||
|
first: number;
|
||||||
|
},
|
||||||
fetchPolicy: FetchPolicy = 'no-cache'
|
fetchPolicy: FetchPolicy = 'no-cache'
|
||||||
): Subscribe<Data, Delta> {
|
): Subscribe<Data, Delta> {
|
||||||
// list of callbacks passed through subscribe call
|
// list of callbacks passed through subscribe call
|
||||||
@ -70,20 +119,60 @@ function makeDataProviderInternal<QueryData, Data, SubscriptionData, Delta>(
|
|||||||
let loading = false;
|
let loading = false;
|
||||||
let client: ApolloClient<object> | undefined = undefined;
|
let client: ApolloClient<object> | undefined = undefined;
|
||||||
let subscription: Subscription | undefined = undefined;
|
let subscription: Subscription | undefined = undefined;
|
||||||
|
let pageInfo: PageInfo | null = null;
|
||||||
|
let totalCount: number | undefined;
|
||||||
|
|
||||||
// notify single callback about current state, delta is passes optionally only if notify was invoked onNext
|
// notify single callback about current state, delta is passes optionally only if notify was invoked onNext
|
||||||
const notify = (callback: UpdateCallback<Data, Delta>, delta?: Delta) => {
|
const notify = (
|
||||||
|
callback: UpdateCallback<Data, Delta>,
|
||||||
|
dataUpdate?: { delta?: Delta; insertionData?: Data | null }
|
||||||
|
) => {
|
||||||
callback({
|
callback({
|
||||||
data,
|
data,
|
||||||
error,
|
error,
|
||||||
loading,
|
loading,
|
||||||
delta,
|
pageInfo,
|
||||||
|
totalCount,
|
||||||
|
...dataUpdate,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// notify all callbacks
|
// notify all callbacks
|
||||||
const notifyAll = (delta?: Delta) => {
|
const notifyAll = (dataUpdate?: {
|
||||||
callbacks.forEach((callback) => notify(callback, delta));
|
delta?: Delta;
|
||||||
|
insertionData?: Data | null;
|
||||||
|
}) => {
|
||||||
|
callbacks.forEach((callback) => notify(callback, dataUpdate));
|
||||||
|
};
|
||||||
|
|
||||||
|
const load = async (params?: Pagination) => {
|
||||||
|
if (!client || !pagination || !pageInfo) {
|
||||||
|
return Promise.reject();
|
||||||
|
}
|
||||||
|
const paginationVariables: Pagination = params ?? {
|
||||||
|
first: pagination.first,
|
||||||
|
after: pageInfo.endCursor,
|
||||||
|
};
|
||||||
|
const res = await client.query<QueryData>({
|
||||||
|
query,
|
||||||
|
variables: {
|
||||||
|
...variables,
|
||||||
|
pagination: paginationVariables,
|
||||||
|
},
|
||||||
|
fetchPolicy,
|
||||||
|
});
|
||||||
|
const insertionData = getData(res.data);
|
||||||
|
const insertionDataPageInfo = pagination.getPageInfo(res.data);
|
||||||
|
({ data, pageInfo } = pagination.append(
|
||||||
|
data,
|
||||||
|
pageInfo,
|
||||||
|
insertionData,
|
||||||
|
insertionDataPageInfo,
|
||||||
|
paginationVariables
|
||||||
|
));
|
||||||
|
totalCount = pagination.getTotalCount(res.data);
|
||||||
|
notifyAll({ insertionData });
|
||||||
|
return insertionData;
|
||||||
};
|
};
|
||||||
|
|
||||||
const initialFetch = async () => {
|
const initialFetch = async () => {
|
||||||
@ -93,10 +182,16 @@ function makeDataProviderInternal<QueryData, Data, SubscriptionData, Delta>(
|
|||||||
try {
|
try {
|
||||||
const res = await client.query<QueryData>({
|
const res = await client.query<QueryData>({
|
||||||
query,
|
query,
|
||||||
variables,
|
variables: pagination
|
||||||
|
? { ...variables, pagination: { first: pagination.first } }
|
||||||
|
: variables,
|
||||||
fetchPolicy,
|
fetchPolicy,
|
||||||
});
|
});
|
||||||
data = getData(res.data);
|
data = getData(res.data);
|
||||||
|
if (pagination) {
|
||||||
|
pageInfo = pagination.getPageInfo(res.data);
|
||||||
|
totalCount = pagination.getTotalCount(res.data);
|
||||||
|
}
|
||||||
// if there was some updates received from subscription during initial query loading apply them on just received data
|
// if there was some updates received from subscription during initial query loading apply them on just received data
|
||||||
if (data && updateQueue && updateQueue.length > 0) {
|
if (data && updateQueue && updateQueue.length > 0) {
|
||||||
while (updateQueue.length) {
|
while (updateQueue.length) {
|
||||||
@ -165,7 +260,7 @@ function makeDataProviderInternal<QueryData, Data, SubscriptionData, Delta>(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
data = newData;
|
data = newData;
|
||||||
notifyAll(delta);
|
notifyAll({ delta });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
() => reload()
|
() => reload()
|
||||||
@ -205,6 +300,7 @@ function makeDataProviderInternal<QueryData, Data, SubscriptionData, Delta>(
|
|||||||
unsubscribe: () => unsubscribe(callback),
|
unsubscribe: () => unsubscribe(callback),
|
||||||
reload,
|
reload,
|
||||||
flush: () => notify(callback),
|
flush: () => notify(callback),
|
||||||
|
load,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -239,7 +335,7 @@ const memoize = <Data, Delta>(
|
|||||||
* @param update Update<Data, Delta> function that will be executed on each onNext, it should update data base on delta, it can reload data provider
|
* @param update Update<Data, Delta> function that will be executed on each onNext, it should update data base on delta, it can reload data provider
|
||||||
* @param getData transforms received query data to format that will be stored in data provider
|
* @param getData transforms received query data to format that will be stored in data provider
|
||||||
* @param getDelta transforms delta data to format that will be stored in data provider
|
* @param getDelta transforms delta data to format that will be stored in data provider
|
||||||
* @param fetchPolicy
|
* @param pagination pagination related functions { getPageInfo, getTotalCount, append, first }
|
||||||
* @returns Subscribe<Data, Delta> subscribe function
|
* @returns Subscribe<Data, Delta> subscribe function
|
||||||
* @example
|
* @example
|
||||||
* const marketMidPriceProvider = makeDataProvider<QueryData, Data, SubscriptionData, Delta>(
|
* const marketMidPriceProvider = makeDataProvider<QueryData, Data, SubscriptionData, Delta>(
|
||||||
@ -263,6 +359,12 @@ export function makeDataProvider<QueryData, Data, SubscriptionData, Delta>(
|
|||||||
update: Update<Data, Delta>,
|
update: Update<Data, Delta>,
|
||||||
getData: GetData<QueryData, Data>,
|
getData: GetData<QueryData, Data>,
|
||||||
getDelta: GetDelta<SubscriptionData, Delta>,
|
getDelta: GetDelta<SubscriptionData, Delta>,
|
||||||
|
pagination?: {
|
||||||
|
getPageInfo: GetPageInfo<QueryData>;
|
||||||
|
getTotalCount: GetTotalCount<QueryData>;
|
||||||
|
append: Append<Data>;
|
||||||
|
first: number;
|
||||||
|
},
|
||||||
fetchPolicy: FetchPolicy = 'no-cache'
|
fetchPolicy: FetchPolicy = 'no-cache'
|
||||||
): Subscribe<Data, Delta> {
|
): Subscribe<Data, Delta> {
|
||||||
const getInstance = memoize<Data, Delta>(() =>
|
const getInstance = memoize<Data, Delta>(() =>
|
||||||
@ -272,6 +374,7 @@ export function makeDataProvider<QueryData, Data, SubscriptionData, Delta>(
|
|||||||
update,
|
update,
|
||||||
getData,
|
getData,
|
||||||
getDelta,
|
getDelta,
|
||||||
|
pagination,
|
||||||
fetchPolicy
|
fetchPolicy
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
@ -8,6 +8,8 @@ module.exports = {
|
|||||||
midGrey: '#828282',
|
midGrey: '#828282',
|
||||||
borderGrey: '#4f4f4f',
|
borderGrey: '#4f4f4f',
|
||||||
lightGrey: '#F2F2F2',
|
lightGrey: '#F2F2F2',
|
||||||
|
lightGreen: '#00f780',
|
||||||
|
darkerGreen: '#008f4A',
|
||||||
yellow: '#DFFF0B',
|
yellow: '#DFFF0B',
|
||||||
mint: '#00F780',
|
mint: '#00F780',
|
||||||
pink: '#FF077F',
|
pink: '#FF077F',
|
||||||
@ -18,6 +20,9 @@ module.exports = {
|
|||||||
'highlight-item-dark': '#fff',
|
'highlight-item-dark': '#fff',
|
||||||
},
|
},
|
||||||
'dropdown-bg-dark': theme.colors.black['100'],
|
'dropdown-bg-dark': theme.colors.black['100'],
|
||||||
|
lite: {
|
||||||
|
black: '#080808',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
fontSize: {
|
fontSize: {
|
||||||
...theme.fontSize,
|
...theme.fontSize,
|
||||||
|
@ -48,6 +48,9 @@ const vegaCustomClasses = plugin(function ({ addUtilities }) {
|
|||||||
'.color-scheme-dark': {
|
'.color-scheme-dark': {
|
||||||
colorScheme: 'dark',
|
colorScheme: 'dark',
|
||||||
},
|
},
|
||||||
|
'.clip-path-rounded': {
|
||||||
|
clipPath: 'circle(50%)',
|
||||||
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ import { useCallback, useMemo, useRef } from 'react';
|
|||||||
import {
|
import {
|
||||||
MAX_TRADES,
|
MAX_TRADES,
|
||||||
sortTrades,
|
sortTrades,
|
||||||
tradesDataProvider,
|
tradesDataProvider as dataProvider,
|
||||||
} from './trades-data-provider';
|
} from './trades-data-provider';
|
||||||
import { TradesTable } from './trades-table';
|
import { TradesTable } from './trades-table';
|
||||||
import type { TradeFields } from './__generated__/TradeFields';
|
import type { TradeFields } from './__generated__/TradeFields';
|
||||||
@ -22,7 +22,7 @@ export const TradesContainer = ({ marketId }: TradesContainerProps) => {
|
|||||||
() => ({ marketId, maxTrades: MAX_TRADES }),
|
() => ({ marketId, maxTrades: MAX_TRADES }),
|
||||||
[marketId]
|
[marketId]
|
||||||
);
|
);
|
||||||
const update = useCallback((delta: TradeFields[]) => {
|
const update = useCallback(({ delta }: { delta: TradeFields[] }) => {
|
||||||
if (!gridRef.current?.api) {
|
if (!gridRef.current?.api) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -43,11 +43,11 @@ export const TradesContainer = ({ marketId }: TradesContainerProps) => {
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}, []);
|
}, []);
|
||||||
const { data, error, loading } = useDataProvider(
|
const { data, error, loading } = useDataProvider({
|
||||||
tradesDataProvider,
|
dataProvider,
|
||||||
update,
|
update,
|
||||||
variables
|
variables,
|
||||||
);
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AsyncRenderer
|
<AsyncRenderer
|
||||||
|
@ -53,8 +53,8 @@ export const sortTrades = (trades: TradeFields[]) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const update = (data: TradeFields[], delta: TradeFields[]) =>
|
const update = (data: TradeFields[], delta: TradeFields[]) => {
|
||||||
produce(data, (draft) => {
|
return produce(data, (draft) => {
|
||||||
const incoming = sortTrades(delta);
|
const incoming = sortTrades(delta);
|
||||||
|
|
||||||
// Add new trades to the top
|
// Add new trades to the top
|
||||||
@ -65,6 +65,7 @@ const update = (data: TradeFields[], delta: TradeFields[]) =>
|
|||||||
draft.splice(MAX_TRADES, draft.length - MAX_TRADES);
|
draft.splice(MAX_TRADES, draft.length - MAX_TRADES);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const getData = (responseData: Trades): TradeFields[] | null =>
|
const getData = (responseData: Trades): TradeFields[] | null =>
|
||||||
responseData.market ? responseData.market.trades : null;
|
responseData.market ? responseData.market.trades : null;
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import React from 'react';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { SunIcon, MoonIcon } from './icons';
|
import { SunIcon, MoonIcon } from './icons';
|
||||||
|
|
||||||
@ -19,7 +20,12 @@ export const ThemeSwitcher = ({
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<button type="button" onClick={() => onToggle()} className={className}>
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => onToggle()}
|
||||||
|
className={className}
|
||||||
|
data-testid="theme-switcher"
|
||||||
|
>
|
||||||
<span className={sunClasses}>
|
<span className={sunClasses}>
|
||||||
<SunIcon />
|
<SunIcon />
|
||||||
</span>
|
</span>
|
||||||
|
@ -1,10 +1,15 @@
|
|||||||
import { render } from '@testing-library/react';
|
import { render } from '@testing-library/react';
|
||||||
|
|
||||||
import { VegaLogo } from './vega-logo';
|
import { VegaLogo, VLogo } from './vega-logo';
|
||||||
|
|
||||||
describe('Vega logo', () => {
|
describe('Vega logo', () => {
|
||||||
it('should render successfully', () => {
|
it('should render successfully', () => {
|
||||||
const { baseElement } = render(<VegaLogo />);
|
const { baseElement } = render(<VegaLogo />);
|
||||||
expect(baseElement).toBeTruthy();
|
expect(baseElement).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('V version should render successfully', () => {
|
||||||
|
const { baseElement } = render(<VLogo />);
|
||||||
|
expect(baseElement).toBeTruthy();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import type { Story, Meta } from '@storybook/react';
|
import type { Story, Meta } from '@storybook/react';
|
||||||
import { VegaLogo } from './vega-logo';
|
import { VegaLogo, VLogo } from './vega-logo';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
component: VegaLogo,
|
component: VegaLogo,
|
||||||
@ -7,5 +7,7 @@ export default {
|
|||||||
} as Meta;
|
} as Meta;
|
||||||
|
|
||||||
const Template: Story = () => <VegaLogo />;
|
const Template: Story = () => <VegaLogo />;
|
||||||
|
const TemplateVLogo: Story = () => <VLogo />;
|
||||||
|
|
||||||
export const Default = Template.bind({});
|
export const Default = Template.bind({});
|
||||||
|
export const VVersion = TemplateVLogo.bind({});
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { t } from '@vegaprotocol/react-helpers';
|
import { t } from '@vegaprotocol/react-helpers';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
export const VegaLogo = () => {
|
export const VegaLogo = () => {
|
||||||
return (
|
return (
|
||||||
@ -16,3 +17,23 @@ export const VegaLogo = () => {
|
|||||||
</svg>
|
</svg>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const VLogo = () => {
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
aria-label={t('Vega logo')}
|
||||||
|
width="29"
|
||||||
|
height="34"
|
||||||
|
fill="currentColor"
|
||||||
|
viewBox="0 0 29 34"
|
||||||
|
className="mx-20 my-16"
|
||||||
|
>
|
||||||
|
<path d="M14.5003 29.1426H9.6665V34.0001H14.5003V29.1426Z" />
|
||||||
|
<path d="M19.3343 24.2859H14.5005V29.1434H19.3343V24.2859Z" />
|
||||||
|
<path d="M29.0008 19.4282H24.167V24.2857H29.0008V19.4282Z" />
|
||||||
|
<path d="M24.1673 0H19.3335V19.4283H24.1673V0Z" />
|
||||||
|
<path d="M9.66776 24.2859H4.83398V29.1434H9.66776V24.2859Z" />
|
||||||
|
<path d="M4.83378 0H0V24.2858H4.83378V0Z" />
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
14
yarn.lock
14
yarn.lock
@ -7437,14 +7437,14 @@ aes-js@^3.1.2:
|
|||||||
integrity sha512-e5pEa2kBnBOgR4Y/p20pskXI74UEz7de8ZGVo58asOtvSVG5YAbJeELPZxOmt+Bnz3rX753YKhfIn4X4l1PPRQ==
|
integrity sha512-e5pEa2kBnBOgR4Y/p20pskXI74UEz7de8ZGVo58asOtvSVG5YAbJeELPZxOmt+Bnz3rX753YKhfIn4X4l1PPRQ==
|
||||||
|
|
||||||
ag-grid-community@^27.0.1:
|
ag-grid-community@^27.0.1:
|
||||||
version "27.1.0"
|
version "27.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/ag-grid-community/-/ag-grid-community-27.1.0.tgz#17f73173444a9efc4faea0f0cd6c5090e698f7ee"
|
resolved "https://registry.yarnpkg.com/ag-grid-community/-/ag-grid-community-27.3.0.tgz#b1e94a58026aaf2f0cd7920e35833325b5e762c7"
|
||||||
integrity sha512-SWzIJTNa7C6Vinizelcoc1FAJQRt1pDn+A8XHQDO2GTQT+VjBnPL8fg94fLJy0EEvqaN5IhDybNS0nD07SKIQw==
|
integrity sha512-R5oZMXEHXnOLrmhn91J8lR0bv6IAnRcU6maO+wKLMJxffRWaAYFAuw1jt7bdmcKCv8c65F6LEBx4ykSOALa9vA==
|
||||||
|
|
||||||
ag-grid-react@^27.0.1:
|
ag-grid-react@^27.0.1:
|
||||||
version "27.1.0"
|
version "27.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/ag-grid-react/-/ag-grid-react-27.1.0.tgz#3b08203b9731a2b2d5431dddd69d68dc640c311e"
|
resolved "https://registry.yarnpkg.com/ag-grid-react/-/ag-grid-react-27.3.0.tgz#fe06647653f8b0b349b8e613aab8ea2e07915562"
|
||||||
integrity sha512-AfRwH6BL/LribvLJ2594Fq0/MfZf/17WebjGj927bM3vABDr2OBX3qgMIaQE+kpV9mABPb51rlWLMmbCvltv2g==
|
integrity sha512-2bs9YfJ/shvBZQLLjny4NFvht+ic6VtpTPO0r3bHHOhlL3Fjx2rGvS6AHSwfvu+kJacHCta30PjaEbX8T3UDyw==
|
||||||
dependencies:
|
dependencies:
|
||||||
prop-types "^15.8.1"
|
prop-types "^15.8.1"
|
||||||
|
|
||||||
@ -17018,7 +17018,7 @@ nx@13.8.1:
|
|||||||
object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1:
|
object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1:
|
||||||
version "4.1.1"
|
version "4.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
|
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
|
||||||
integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
|
integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==
|
||||||
|
|
||||||
object-copy@^0.1.0:
|
object-copy@^0.1.0:
|
||||||
version "0.1.0"
|
version "0.1.0"
|
||||||
|
Loading…
Reference in New Issue
Block a user