chore(orders): 4970 add no rows and error info (#5076)

This commit is contained in:
Maciek 2023-10-19 15:45:55 +02:00 committed by GitHub
parent a98ab775c3
commit 2dfcb02d1e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 102 additions and 27 deletions

View File

@ -10,6 +10,19 @@ import type { DataGridStore } from '../../stores/datagrid-store-slice';
import { OrderStatus } from '@vegaprotocol/types'; import { OrderStatus } from '@vegaprotocol/types';
import { Links } from '../../lib/links'; import { Links } from '../../lib/links';
const resolveNoRowsMessage = (filter?: Filter) => {
switch (filter) {
case Filter.Open:
return t('No open orders');
case Filter.Closed:
return t('No closed orders');
case Filter.Rejected:
return t('No rejected orders');
default:
return t('No orders');
}
};
export const FilterStatusValue = { export const FilterStatusValue = {
[Filter.Open]: [OrderStatus.STATUS_ACTIVE, OrderStatus.STATUS_PARKED], [Filter.Open]: [OrderStatus.STATUS_ACTIVE, OrderStatus.STATUS_PARKED],
[Filter.Closed]: [ [Filter.Closed]: [
@ -43,6 +56,7 @@ export const OrdersContainer = ({ filter }: OrderContainerProps) => {
if (!pubKey) { if (!pubKey) {
return <Splash>{t('Please connect Vega wallet')}</Splash>; return <Splash>{t('Please connect Vega wallet')}</Splash>;
} }
const noRowsMessage = resolveNoRowsMessage(filter);
return ( return (
<OrderListManager <OrderListManager
@ -56,6 +70,7 @@ export const OrdersContainer = ({ filter }: OrderContainerProps) => {
} }
isReadOnly={isReadOnly} isReadOnly={isReadOnly}
gridProps={gridStoreCallbacks} gridProps={gridStoreCallbacks}
noRowsMessage={noRowsMessage}
/> />
); );
}; };

View File

@ -63,7 +63,9 @@ export const CandlesChartContainer = ({
overlays, overlays,
studies, studies,
notEnoughDataText: ( notEnoughDataText: (
<span className="text-xs text-center">{t('No data')}</span> <span className="text-xs text-center">
{t('No open orders')}
</span>
), ),
initialNumCandlesToDisplay: candlesCount, initialNumCandlesToDisplay: candlesCount,
studySize: STUDY_SIZE, studySize: STUDY_SIZE,

View File

@ -238,7 +238,7 @@ export const DepthChartContainer = ({ marketId }: DepthChartManagerProps) => {
volumeFormat={volumeFormat} volumeFormat={volumeFormat}
priceFormat={priceFormat} priceFormat={priceFormat}
notEnoughDataText={ notEnoughDataText={
<span className="text-xs text-center">{t('No data')}</span> <span className="text-xs text-center">{t('No open orders')}</span>
} }
/> />
)} )}

View File

@ -11,14 +11,8 @@ import type {
MarketDepthQuery, MarketDepthQuery,
MarketDepthQueryVariables, MarketDepthQueryVariables,
MarketDepthUpdateSubscription, MarketDepthUpdateSubscription,
PriceLevelFieldsFragment,
} from './__generated__/MarketDepth'; } from './__generated__/MarketDepth';
export type OrderbookData = {
asks: PriceLevelFieldsFragment[];
bids: PriceLevelFieldsFragment[];
};
interface OrderbookManagerProps { interface OrderbookManagerProps {
marketId: string; marketId: string;
onClick: (args: { price?: string; size?: string }) => void; onClick: (args: { price?: string; size?: string }) => void;

View File

@ -238,7 +238,7 @@ export const Orderbook = ({
</> </>
) : ( ) : (
<div className="absolute inset-0"> <div className="absolute inset-0">
<Splash>{t('No data')}</Splash> <Splash>{t('No open orders')}</Splash>
</div> </div>
)} )}
</div> </div>

View File

@ -1,23 +1,18 @@
import { render, screen, act } from '@testing-library/react'; import { render, screen } from '@testing-library/react';
import { OrderListManager } from './order-list-manager'; import type { OrderListManagerProps } from './order-list-manager';
import { OrderListManager, Filter } from './order-list-manager';
import * as useDataProviderHook from '@vegaprotocol/data-provider'; import * as useDataProviderHook from '@vegaprotocol/data-provider';
import type { OrderFieldsFragment } from '../'; import type { OrderFieldsFragment } from '../';
import * as orderListMock from '../order-list/order-list';
import { forwardRef } from 'react';
import type { VegaWalletContextShape } from '@vegaprotocol/wallet'; import type { VegaWalletContextShape } from '@vegaprotocol/wallet';
import { VegaWalletContext } from '@vegaprotocol/wallet'; import { VegaWalletContext } from '@vegaprotocol/wallet';
import { MockedProvider } from '@apollo/client/testing'; import { MockedProvider } from '@apollo/client/testing';
// @ts-ignore OrderList is read only but we need to override with the forwardRef to const generateJsx = (props: Partial<OrderListManagerProps> | null = null) => {
// avoid warnings about padding refs
orderListMock.OrderListTable = forwardRef(() => <div>OrderList</div>);
const generateJsx = () => {
const pubKey = '0x123'; const pubKey = '0x123';
return ( return (
<MockedProvider> <MockedProvider>
<VegaWalletContext.Provider value={{ pubKey } as VegaWalletContextShape}> <VegaWalletContext.Provider value={{ pubKey } as VegaWalletContextShape}>
<OrderListManager partyId={pubKey} isReadOnly={false} /> <OrderListManager partyId={pubKey} isReadOnly={false} {...props} />
</VegaWalletContext.Provider> </VegaWalletContext.Provider>
</MockedProvider> </MockedProvider>
); );
@ -33,9 +28,46 @@ describe('OrderListManager', () => {
reload: jest.fn(), reload: jest.fn(),
load: jest.fn(), load: jest.fn(),
}); });
await act(async () => { render(generateJsx());
render(generateJsx());
expect(
await screen.getByRole('treegrid', {
name: (_, element) => element.classList.contains('ag-root'),
})
).toBeInTheDocument();
});
it('should display order info', async () => {
jest.spyOn(useDataProviderHook, 'useDataProvider').mockReturnValue({
data: [{ id: '1' } as OrderFieldsFragment],
loading: false,
error: new Error('Query error'),
flush: jest.fn(),
reload: jest.fn(),
load: jest.fn(),
}); });
expect(await screen.findByText('OrderList')).toBeInTheDocument();
render(generateJsx());
expect(
await screen.getByText('Something went wrong: Query error')
).toBeInTheDocument();
});
it('should display no rows overlay', async () => {
jest.spyOn(useDataProviderHook, 'useDataProvider').mockReturnValue({
data: [],
loading: false,
error: undefined,
flush: jest.fn(),
reload: jest.fn(),
load: jest.fn(),
});
render(
generateJsx({ filter: Filter.Closed, noRowsMessage: 'no rows message' })
);
expect(screen.getByText('no rows message')).toBeInTheDocument();
}); });
}); });

View File

@ -1,7 +1,8 @@
import { t } from '@vegaprotocol/i18n'; import { t } from '@vegaprotocol/i18n';
import { useCallback, useRef, useState } from 'react'; import { useCallback, useRef, useState, useEffect } from 'react';
import type { AgGridReact } from 'ag-grid-react'; import type { AgGridReact } from 'ag-grid-react';
import { OrderListTable } from '../order-list/order-list'; import type { FilterChangedEvent } from 'ag-grid-community';
import { OrderListTable } from '../order-list';
import type { useDataGridEvents } from '@vegaprotocol/datagrid'; import type { useDataGridEvents } from '@vegaprotocol/datagrid';
import { useDataProvider } from '@vegaprotocol/data-provider'; import { useDataProvider } from '@vegaprotocol/data-provider';
import { ordersWithMarketProvider } from '../order-data-provider/order-data-provider'; import { ordersWithMarketProvider } from '../order-data-provider/order-data-provider';
@ -11,6 +12,7 @@ import type { OrderTxUpdateFieldsFragment } from '@vegaprotocol/web3';
import { OrderEditDialog } from '../order-list/order-edit-dialog'; import { OrderEditDialog } from '../order-list/order-edit-dialog';
import type { Order } from '../order-data-provider'; import type { Order } from '../order-data-provider';
import { OrderViewDialog } from '../order-list/order-view-dialog'; import { OrderViewDialog } from '../order-list/order-view-dialog';
import { Splash } from '@vegaprotocol/ui-toolkit';
export enum Filter { export enum Filter {
'Open' = 'Open', 'Open' = 'Open',
@ -25,6 +27,7 @@ export interface OrderListManagerProps {
isReadOnly: boolean; isReadOnly: boolean;
filter?: Filter; filter?: Filter;
gridProps?: ReturnType<typeof useDataGridEvents>; gridProps?: ReturnType<typeof useDataGridEvents>;
noRowsMessage?: string;
} }
export const OrderListManager = ({ export const OrderListManager = ({
@ -34,6 +37,7 @@ export const OrderListManager = ({
isReadOnly, isReadOnly,
filter, filter,
gridProps, gridProps,
noRowsMessage,
}: OrderListManagerProps) => { }: OrderListManagerProps) => {
const gridRef = useRef<AgGridReact | null>(null); const gridRef = useRef<AgGridReact | null>(null);
const [editOrder, setEditOrder] = useState<Order | null>(null); const [editOrder, setEditOrder] = useState<Order | null>(null);
@ -56,6 +60,29 @@ export const OrderListManager = ({
}, },
}); });
const onFilterChanged = useCallback(
(event: FilterChangedEvent) => {
gridProps?.onFilterChanged?.(event);
if (event.api) {
const isEmpty = event.api.getDisplayedRowCount() === 0;
if (isEmpty) {
event.api.showNoRowsOverlay();
} else {
event.api.hideOverlay();
}
}
},
[gridProps]
);
useEffect(() => {
if (!data || !data.length) {
gridRef.current?.api?.showNoRowsOverlay();
} else {
gridRef.current?.api?.hideOverlay();
}
}, [data]);
const cancel = useCallback( const cancel = useCallback(
(order: Order) => { (order: Order) => {
if (!order.market) return; if (!order.market) return;
@ -69,6 +96,10 @@ export const OrderListManager = ({
[create] [create]
); );
if (error) {
return <Splash>{t(`Something went wrong: ${error.message}`)}</Splash>;
}
return ( return (
<> <>
<div className="h-full relative"> <div className="h-full relative">
@ -82,8 +113,9 @@ export const OrderListManager = ({
onMarketClick={onMarketClick} onMarketClick={onMarketClick}
onOrderTypeClick={onOrderTypeClick} onOrderTypeClick={onOrderTypeClick}
isReadOnly={isReadOnly} isReadOnly={isReadOnly}
overlayNoRowsTemplate={error ? error.message : t('No orders')} overlayNoRowsTemplate={noRowsMessage || t('No orders')}
{...gridProps} {...gridProps}
onFilterChanged={onFilterChanged}
/> />
</div> </div>
{editOrder && ( {editOrder && (

View File

@ -34,7 +34,7 @@ import type {
} from '@vegaprotocol/datagrid'; } from '@vegaprotocol/datagrid';
import type { AgGridReact } from 'ag-grid-react'; import type { AgGridReact } from 'ag-grid-react';
import type { Order } from '../order-data-provider'; import type { Order } from '../order-data-provider';
import { Filter } from '../order-list-manager'; import { Filter } from '../order-list-manager/order-list-manager';
import type { ColDef } from 'ag-grid-community'; import type { ColDef } from 'ag-grid-community';
const defaultColDef = { const defaultColDef = {

View File

@ -58,7 +58,7 @@ type ThemeStore = {
setTheme: (theme?: Theme) => void; setTheme: (theme?: Theme) => void;
}; };
const useThemeStore = create<ThemeStore>((set) => ({ const useThemeStore = create<ThemeStore>()((set) => ({
theme: getCurrentTheme(), theme: getCurrentTheme(),
setTheme: (newTheme) => { setTheme: (newTheme) => {
set((state) => { set((state) => {