diff --git a/apps/trading-e2e/src/integration/trading-orders.cy.ts b/apps/trading-e2e/src/integration/trading-orders.cy.ts index af5ef4e11..d22054c04 100644 --- a/apps/trading-e2e/src/integration/trading-orders.cy.ts +++ b/apps/trading-e2e/src/integration/trading-orders.cy.ts @@ -22,7 +22,7 @@ const cancelAllOrdersBtn = 'cancelAll'; const editOrderBtn = 'edit'; describe('orders list', { tags: '@smoke' }, () => { - before(() => { + beforeEach(() => { const subscriptionMocks = getSubscriptionMocks(); cy.spy(subscriptionMocks, 'OrdersUpdate'); cy.mockTradingPage(); @@ -82,6 +82,13 @@ describe('orders list', { tags: '@smoke' }, () => { '94aead3ca92dc932efcb503631b03a410e2a5d4606cae6083e2406dc38e52f78'; cy.getByTestId('tab-orders').should('be.visible'); + cy.get('.ag-header-container').within(() => { + cy.get('[col-id="status"]').realHover(); + cy.get('[col-id="status"] .ag-icon-menu').click(); + }); + cy.contains('Partially Filled').click(); + cy.getByTestId('Orders').click(); + cy.get(`[row-id="${partiallyFilledId}"]`).within(() => { cy.get(`[col-id='${orderStatus}']`).should( 'have.text', @@ -102,6 +109,12 @@ describe('orders list', { tags: '@smoke' }, () => { 'BTCUSD.MF21', 'BTCUSD.MF21', ]; + cy.get('.ag-header-container').within(() => { + cy.get('[col-id="status"]').realHover(); + cy.get('[col-id="status"] .ag-icon-menu').click(); + }); + cy.contains('Reset').click(); + cy.getByTestId('Orders').click(); cy.getByTestId('tab-orders') .get(`.ag-center-cols-container [col-id='${orderSymbol}']`) diff --git a/apps/trading/client-pages/market/trade-grid.tsx b/apps/trading/client-pages/market/trade-grid.tsx index 9809fab99..f8383d1f0 100644 --- a/apps/trading/client-pages/market/trade-grid.tsx +++ b/apps/trading/client-pages/market/trade-grid.tsx @@ -102,6 +102,7 @@ const MarketBottomPanel = memo( @@ -157,6 +158,7 @@ const MarketBottomPanel = memo( diff --git a/libs/orders/src/lib/components/order-list-container.tsx b/libs/orders/src/lib/components/order-list-container.tsx index 5b91ff427..018558702 100644 --- a/libs/orders/src/lib/components/order-list-container.tsx +++ b/libs/orders/src/lib/components/order-list-container.tsx @@ -6,9 +6,11 @@ import { OrderListManager } from './order-list-manager'; export const OrderListContainer = ({ marketId, onMarketClick, + enforceBottomPlaceholder, }: { marketId?: string; onMarketClick?: (marketId: string) => void; + enforceBottomPlaceholder?: boolean; }) => { const { pubKey, isReadOnly } = useVegaWallet(); @@ -22,6 +24,7 @@ export const OrderListContainer = ({ marketId={marketId} onMarketClick={onMarketClick} isReadOnly={isReadOnly} + enforceBottomPlaceholder={enforceBottomPlaceholder} /> ); }; diff --git a/libs/orders/src/lib/components/order-list-manager/order-list-manager.spec.tsx b/libs/orders/src/lib/components/order-list-manager/order-list-manager.spec.tsx index 46f2fd2e7..e3bb64b12 100644 --- a/libs/orders/src/lib/components/order-list-manager/order-list-manager.spec.tsx +++ b/libs/orders/src/lib/components/order-list-manager/order-list-manager.spec.tsx @@ -74,4 +74,20 @@ describe('OrderListManager', () => { }); expect(await screen.findByText('OrderList')).toBeInTheDocument(); }); + + it('should show no orders message', async () => { + jest.spyOn(useDataProviderHook, 'useDataProvider').mockReturnValue({ + data: [], + loading: false, + error: undefined, + flush: jest.fn(), + reload: jest.fn(), + load: jest.fn(), + totalCount: undefined, + }); + await act(async () => { + render(generateJsx()); + }); + expect(screen.getByText('No orders')).toBeInTheDocument(); + }); }); diff --git a/libs/orders/src/lib/components/order-list-manager/order-list-manager.tsx b/libs/orders/src/lib/components/order-list-manager/order-list-manager.tsx index 385588dd8..6b2706e34 100644 --- a/libs/orders/src/lib/components/order-list-manager/order-list-manager.tsx +++ b/libs/orders/src/lib/components/order-list-manager/order-list-manager.tsx @@ -1,12 +1,7 @@ import { AsyncRenderer } from '@vegaprotocol/ui-toolkit'; import { t } from '@vegaprotocol/i18n'; -import { useCallback, useRef, useState } from 'react'; -import type { - BodyScrollEvent, - BodyScrollEndEvent, - FilterChangedEvent, - SortChangedEvent, -} from 'ag-grid-community'; +import { useCallback, useEffect, useRef, useState } from 'react'; +import type { FilterChangedEvent, SortChangedEvent } from 'ag-grid-community'; import { Button } from '@vegaprotocol/ui-toolkit'; import type { AgGridReact } from 'ag-grid-react'; import type { GridReadyEvent } from 'ag-grid-community'; @@ -23,13 +18,14 @@ import { } from '@vegaprotocol/wallet'; import type { OrderTxUpdateFieldsFragment } from '@vegaprotocol/wallet'; import { OrderEditDialog } from '../order-list/order-edit-dialog'; -import type { Order } from '../order-data-provider'; +import type { Order, OrderEdge } from '../order-data-provider'; export interface OrderListManagerProps { partyId: string; marketId?: string; onMarketClick?: (marketId: string) => void; isReadOnly: boolean; + enforceBottomPlaceholder?: boolean; } const CancelAllOrdersButton = ({ @@ -65,78 +61,50 @@ export const OrderListManager = ({ marketId, onMarketClick, isReadOnly, + enforceBottomPlaceholder, }: OrderListManagerProps) => { const gridRef = useRef(null); - const scrolledToTop = useRef(true); + const [dataCount, setDataCount] = useState(0); + const scrolledToTop = useRef(false); const [sort, setSort] = useState(); const [filter, setFilter] = useState(initialFilter); const [editOrder, setEditOrder] = useState(null); const create = useVegaTransactionStore((state) => state.create); const hasActiveOrder = useHasActiveOrder(marketId); - const { - data, - error, - loading, - addNewRows, - getRows, - reload, - makeBottomPlaceholders, - } = useOrderListData({ + const { data, error, loading, reload } = useOrderListData({ partyId, - marketId, sort, filter, gridRef, scrolledToTop, }); - const checkBottomPlaceholder = useCallback(() => { - if (!isReadOnly && hasActiveOrder) { - const rowCont = gridRef.current?.api?.getModel().getRowCount() ?? 0; - const lastRowIndex = gridRef.current?.api?.getLastDisplayedRow(); - if (lastRowIndex && rowCont - 1 === lastRowIndex) { - const lastrow = - gridRef.current?.api.getDisplayedRowAtIndex(lastRowIndex); - lastrow?.setRowHeight(50); - makeBottomPlaceholders(lastrow?.data); - gridRef.current?.api.onRowHeightChanged(); - gridRef.current?.api.refreshInfiniteCache(); - } - } - }, [isReadOnly, hasActiveOrder, makeBottomPlaceholders]); - - const onBodyScrollEnd = useCallback( - (event: BodyScrollEndEvent) => { - if (event.top === 0) { - addNewRows(); - } - checkBottomPlaceholder(); - }, - [addNewRows, checkBottomPlaceholder] - ); - - const onBodyScroll = useCallback((event: BodyScrollEvent) => { - scrolledToTop.current = event.top <= 0; - }, []); + const { + onSortChanged: bottomPlaceholderOnSortChanged, + onFilterChanged: bottomPlaceholderOnFilterChanged, + ...bottomPlaceholderProps + } = useBottomPlaceholder({ + gridRef, + disabled: !enforceBottomPlaceholder && !isReadOnly && !hasActiveOrder, + }); const onFilterChanged = useCallback( (event: FilterChangedEvent) => { - makeBottomPlaceholders(); const updatedFilter = event.api.getFilterModel(); if (Object.keys(updatedFilter).length) { setFilter(updatedFilter); } else { setFilter(undefined); } - checkBottomPlaceholder(); + setDataCount(gridRef.current?.api?.getModel().getRowCount() ?? 0); + bottomPlaceholderOnFilterChanged?.(); }, - [setFilter, makeBottomPlaceholders, checkBottomPlaceholder] + [setFilter, bottomPlaceholderOnFilterChanged] ); const onSortChange = useCallback( (event: SortChangedEvent) => { - makeBottomPlaceholders(); const sort = event.columnApi .getColumnState() .sort((a, b) => (a.sortIndex || 0) - (b.sortIndex || 0)) @@ -148,9 +116,9 @@ export const OrderListManager = ({ return acc; }, [] as { colId: string; sort: string }[]); setSort(sort.length > 0 ? sort : undefined); - checkBottomPlaceholder(); + bottomPlaceholderOnSortChanged?.(); }, - [setSort, makeBottomPlaceholders, checkBottomPlaceholder] + [setSort, bottomPlaceholderOnSortChanged] ); const cancel = useCallback( @@ -166,15 +134,13 @@ export const OrderListManager = ({ [create] ); - const onGridReady = useCallback( - ({ api }: GridReadyEvent) => { - api.setDatasource({ - getRows, - }); - api.setFilterModel(initialFilter); - }, - [getRows] - ); + const onGridReady = useCallback(({ api }: GridReadyEvent) => { + api.setFilterModel(initialFilter); + }, []); + + useEffect(() => { + setDataCount(gridRef.current?.api?.getModel().getRowCount() ?? 0); + }, [data]); const cancelAll = useCallback( (marketId?: string) => { @@ -186,20 +152,20 @@ export const OrderListManager = ({ }, [create] ); - const { isFullWidthRow, fullWidthCellRenderer, rowClassRules } = - useBottomPlaceholder({ - gridRef, - }); + const extractedData = + data && !loading + ? data + .filter((item) => item !== null) + .map((item) => (item as OrderEdge).node) + : null; return ( <>
!(data && data.length)} + noDataCondition={(data) => !dataCount} reload={reload} />
diff --git a/libs/orders/src/lib/components/order-list-manager/use-order-list-data.ts b/libs/orders/src/lib/components/order-list-manager/use-order-list-data.ts index 53bcf2bfc..4a5200284 100644 --- a/libs/orders/src/lib/components/order-list-manager/use-order-list-data.ts +++ b/libs/orders/src/lib/components/order-list-manager/use-order-list-data.ts @@ -79,6 +79,9 @@ export const useOrderListData = ({ timeInForce: filter?.timeInForce?.value, types: filter?.type?.value, }, + pagination: { + first: 1000, + }, }), [partyId, marketId, filter] ); @@ -98,7 +101,6 @@ export const useOrderListData = ({ ({ data, delta, - totalCount, }: { data: (OrderEdge | null)[] | null; delta?: Order[]; @@ -112,7 +114,10 @@ export const useOrderListData = ({ ).length; } } - return updateGridData(dataRef, data, gridRef); + if (gridRef.current?.api?.getModel().getType() === 'infinite') { + return updateGridData(dataRef, data, gridRef); + } + return false; }, [gridRef, scrolledToTop] ); @@ -126,7 +131,10 @@ export const useOrderListData = ({ totalCount?: number; }) => { totalCountRef.current = totalCount; - return updateGridData(dataRef, data, gridRef); + if (gridRef.current?.api?.getModel().getType() === 'infinite') { + return updateGridData(dataRef, data, gridRef); + } + return false; }, [gridRef] ); diff --git a/libs/orders/src/lib/components/order-list/order-list.spec.tsx b/libs/orders/src/lib/components/order-list/order-list.spec.tsx index 2e5d59099..20f66106e 100644 --- a/libs/orders/src/lib/components/order-list/order-list.spec.tsx +++ b/libs/orders/src/lib/components/order-list/order-list.spec.tsx @@ -48,7 +48,9 @@ describe('OrderListTable', () => { await act(async () => { render(generateJsx({ rowData: [] })); }); - expect(screen.getByText('No orders')).toBeInTheDocument(); + expect(() => screen.getByText('No orders')).toThrow( + 'Unable to find an element' + ); }); it('should render correct columns', async () => { diff --git a/libs/orders/src/lib/components/order-list/order-list.tsx b/libs/orders/src/lib/components/order-list/order-list.tsx index 61c6ebde8..c1d2e7ec6 100644 --- a/libs/orders/src/lib/components/order-list/order-list.tsx +++ b/libs/orders/src/lib/components/order-list/order-list.tsx @@ -39,10 +39,10 @@ export const OrderListTable = memo( return ( ) => { if (!data) { return undefined; @@ -110,6 +110,7 @@ export const OrderListTable = memo( ) ); }} + minWidth={80} /> ) => { if (!order) { return undefined; @@ -130,6 +130,7 @@ export const OrderListTable = memo( if (order?.liquidityProvision) return t('Liquidity provision'); return Schema.OrderTypeMapping[value]; }} + minWidth={80} /> )} + minWidth={100} /> ); }} + minWidth={150} /> ); }} + minWidth={150} /> ) : null; }} + sortable={false} /> ); diff --git a/libs/react-helpers/src/hooks/use-bottom-placeholder.tsx b/libs/react-helpers/src/hooks/use-bottom-placeholder.tsx index 1bce82078..2e0ab70e2 100644 --- a/libs/react-helpers/src/hooks/use-bottom-placeholder.tsx +++ b/libs/react-helpers/src/hooks/use-bottom-placeholder.tsx @@ -68,7 +68,7 @@ export const useBottomPlaceholder = ({ isFullWidthRow, fullWidthCellRenderer, onSortChanged: onRowsChanged, - onFilterChange: onRowsChanged, + onFilterChanged: onRowsChanged, } : {}, [onBodyScrollEnd, onRowsChanged, disabled] diff --git a/libs/utils/src/lib/generic-data-provider.ts b/libs/utils/src/lib/generic-data-provider.ts index c03405c06..7a14f1b4c 100644 --- a/libs/utils/src/lib/generic-data-provider.ts +++ b/libs/utils/src/lib/generic-data-provider.ts @@ -258,7 +258,16 @@ function makeDataProviderInternal< client .query({ query, - variables: { ...variables, ...(pagination && { pagination }) }, + variables: { + ...variables, + ...(pagination && { + // let the variables pagination be prior to provider param + pagination: { + ...pagination, + ...(variables?.['pagination'] ?? null), + }, + }), + }, fetchPolicy: fetchPolicy || 'no-cache', context: additionalContext, errorPolicy: policy || 'none',