feat(trading): market view persistent pane sizes (#3537)

This commit is contained in:
Maciek 2023-05-03 10:44:45 +02:00 committed by GitHub
parent 4a4cdaa2b8
commit 7a99ded8e9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 110 additions and 25 deletions

View File

@ -27,7 +27,10 @@ import { NO_MARKET } from './constants';
import { LiquidityContainer } from '../liquidity/liquidity';
import { useNavigate } from 'react-router-dom';
import type { PinnedAsset } from '@vegaprotocol/accounts';
import { useScreenDimensions } from '@vegaprotocol/react-helpers';
import {
usePaneLayout,
useScreenDimensions,
} from '@vegaprotocol/react-helpers';
import {
useMarketClickHandler,
useMarketLiquidityClickHandler,
@ -83,15 +86,20 @@ interface BottomPanelProps {
const MarketBottomPanel = memo(
({ marketId, pinnedAsset }: BottomPanelProps) => {
const [sizes, handleOnLayoutChange] = usePaneLayout({ id: 'bottom' });
const { screenSize } = useScreenDimensions();
const onMarketClick = useMarketClickHandler(true);
const onOrderTypeClick = useMarketLiquidityClickHandler(true);
return 'xxxl' === screenSize ? (
<ResizableGrid proportionalLayout minSize={200}>
<ResizableGrid
proportionalLayout
minSize={200}
onChange={handleOnLayoutChange}
>
<ResizableGridPanel
priority={LayoutPriority.Low}
preferredSize="50%"
preferredSize={sizes[0] || '50%'}
minSize={50}
>
<TradeGridChild>
@ -119,7 +127,7 @@ const MarketBottomPanel = memo(
</ResizableGridPanel>
<ResizableGridPanel
priority={LayoutPriority.Low}
preferredSize="50%"
preferredSize={sizes[1] || '50%'}
minSize={50}
>
<TradeGridChild>
@ -186,22 +194,29 @@ MarketBottomPanel.displayName = 'MarketBottomPanel';
const MainGrid = memo(
({
marketId,
onSelect,
pinnedAsset,
}: {
marketId: string;
onSelect: (marketId: string, metaKey?: boolean) => void;
pinnedAsset?: PinnedAsset;
}) => {
const navigate = useNavigate();
const [sizes, handleOnLayoutChange] = usePaneLayout({ id: 'top' });
const [sizesMiddle, handleOnMiddleLayoutChange] = usePaneLayout({
id: 'middle',
});
return (
<ResizableGrid vertical>
<ResizableGrid vertical onChange={handleOnLayoutChange}>
<ResizableGridPanel minSize={75} priority={LayoutPriority.High}>
<ResizableGrid proportionalLayout={false} minSize={200}>
<ResizableGrid
proportionalLayout={false}
minSize={200}
onChange={handleOnMiddleLayoutChange}
>
<ResizableGridPanel
priority={LayoutPriority.High}
minSize={200}
preferredSize="50%"
preferredSize={sizesMiddle[0] || '50%'}
>
<TradeGridChild>
<Tabs storageKey="console-trade-grid-main-left">
@ -219,7 +234,7 @@ const MainGrid = memo(
</ResizableGridPanel>
<ResizableGridPanel
priority={LayoutPriority.Low}
preferredSize={330}
preferredSize={sizesMiddle[1] || 330}
minSize={300}
>
<TradeGridChild>
@ -238,7 +253,7 @@ const MainGrid = memo(
</ResizableGridPanel>
<ResizableGridPanel
priority={LayoutPriority.Low}
preferredSize={430}
preferredSize={sizesMiddle[2] || 430}
minSize={200}
>
<TradeGridChild>
@ -256,7 +271,7 @@ const MainGrid = memo(
</ResizableGridPanel>
<ResizableGridPanel
priority={LayoutPriority.Low}
preferredSize="25%"
preferredSize={sizes[1] || '25%'}
minSize={50}
>
<MarketBottomPanel marketId={marketId} pinnedAsset={pinnedAsset} />
@ -278,11 +293,7 @@ export const TradeGrid = ({
<TradeMarketHeader market={market} onSelect={onSelect} />
<OracleBanner marketId={market?.id || ''} />
</div>
<MainGrid
marketId={market?.id || ''}
onSelect={onSelect}
pinnedAsset={pinnedAsset}
/>
<MainGrid marketId={market?.id || ''} pinnedAsset={pinnedAsset} />
</div>
);
};

View File

@ -7,6 +7,7 @@ import { WithdrawalsContainer } from './withdrawals-container';
import { FillsContainer } from '@vegaprotocol/fills';
import type { ReactNode } from 'react';
import { useEffect } from 'react';
import { usePaneLayout } from '@vegaprotocol/react-helpers';
import { VegaWalletContainer } from '../../components/vega-wallet-container';
import { DepositsContainer } from './deposits-container';
import { LayoutPriority } from 'allotment';
@ -34,11 +35,11 @@ export const Portfolio = () => {
const onMarketClick = useMarketClickHandler(true);
const onOrderTypeClick = useMarketLiquidityClickHandler(true);
const [sizes, handleOnLayoutChange] = usePaneLayout({ id: 'portfolio' });
const wrapperClasses = 'h-full max-h-full flex flex-col';
return (
<div className={wrapperClasses}>
<ResizableGrid vertical>
<ResizableGrid vertical onChange={handleOnLayoutChange}>
<ResizableGridPanel minSize={75}>
<PortfolioGridChild>
<Tabs storageKey="console-portfolio-top">
@ -78,7 +79,7 @@ export const Portfolio = () => {
</ResizableGridPanel>
<ResizableGridPanel
priority={LayoutPriority.Low}
preferredSize={300}
preferredSize={sizes[1] || 300}
minSize={50}
>
<PortfolioGridChild>

View File

@ -17,3 +17,4 @@ export * from './use-yesterday';
export * from './use-previous';
export * from './use-logger';
export * from './use-bottom-placeholder';
export * from './use-pane-layout';

View File

@ -0,0 +1,19 @@
import { renderHook, act, waitFor } from '@testing-library/react';
import { usePaneLayout } from './use-pane-layout';
describe('usePaneLayout', () => {
it('should return proper values', () => {
const ret = renderHook(() => usePaneLayout({ id: 'testid' }));
expect(ret.result.current[0]).toStrictEqual([]);
expect(ret.result.current[1]).toStrictEqual(expect.any(Function));
});
it('setter should change value', async () => {
const ret = renderHook(() => usePaneLayout({ id: 'testid' }));
await act(() => {
ret.result.current[1]([100, 50, 50]);
});
await waitFor(() => {
expect(ret.result.current[0]).toStrictEqual(['50%', '25%', '25%']);
});
});
});

View File

@ -0,0 +1,47 @@
import { useCallback } from 'react';
import debounce from 'lodash/debounce';
import { create } from 'zustand';
import { persist } from 'zustand/middleware';
import { immer } from 'zustand/middleware/immer';
const STORAGE_KEY = 'vega_pane_store';
const PANELS_SET_DEBOUNCE_TIME = 300;
export const usePaneLayoutStore = create<{
sizes: Record<string, string[]>;
valueSetter: (id: string, value: string[]) => void;
}>()(
persist(
immer((set) => ({
sizes: {},
valueSetter: (id, value) =>
set((state) => {
state.sizes[id] = value;
return state;
}),
})),
{ name: STORAGE_KEY }
)
);
interface UsePaneLayoutProps {
id: string;
}
export const usePaneLayout = ({
id,
}: UsePaneLayoutProps): [string[], (sizes: number[]) => void] => {
const sizes = usePaneLayoutStore((store) => store.sizes[id]) || [];
const valueSetter = usePaneLayoutStore((store) => store.valueSetter);
// eslint-disable-next-line react-hooks/exhaustive-deps
const handleOnChange = useCallback(
debounce((args) => {
if (args.length) {
const all = args.reduce((agg: number, item: number) => agg + item, 0);
const sizesArr = args.map((arg: number) => `${(arg / all) * 100}%`);
valueSetter(id, sizesArr);
}
}, PANELS_SET_DEBOUNCE_TIME),
[valueSetter, id]
);
return [sizes, handleOnChange];
};

View File

@ -120,7 +120,11 @@ describe('VegaConnectDialog', () => {
.mockImplementation(() =>
Promise.resolve({ success: true, error: null })
);
jest
.spyOn(connectors.rest, 'connect')
.mockImplementation(() =>
Promise.resolve([{ publicKey: 'pubkey', name: 'test key 1' }])
);
render(generateJSX());
// Switches to rest form
fireEvent.click(await screen.findByText('Hosted Fairground wallet'));
@ -138,10 +142,11 @@ describe('VegaConnectDialog', () => {
await act(async () => {
fireEvent.submit(screen.getByTestId('rest-connector-form'));
});
await waitFor(() => {
expect(spy).toHaveBeenCalledWith(fields);
expect(spy).toHaveBeenCalledWith(fields);
expect(mockCloseVegaDialog).toHaveBeenCalled();
expect(mockCloseVegaDialog).toHaveBeenCalled();
});
});
it('handles failed connection', async () => {

View File

@ -24,7 +24,8 @@
"echo $NX_TENDERMINT_WEBSOCKET_URL",
"echo $NX_USE_ENV_OVERRIDES",
"echo $NX_ETHEREUM_PROVIDER_URL"
]
],
"url": "https://cloud.nx.app"
}
}
},