chore(orders): remove infinite scroll from order table (#3247)
Co-authored-by: Matthew Russell <mattrussell36@gmail.com>
This commit is contained in:
parent
b611d30b31
commit
f649d78565
@ -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}']`)
|
||||
|
@ -102,6 +102,7 @@ const MarketBottomPanel = memo(
|
||||
<TradingViews.Orders
|
||||
marketId={marketId}
|
||||
onMarketClick={onMarketClick}
|
||||
enforceBottomPlaceholder
|
||||
/>
|
||||
</VegaWalletContainer>
|
||||
</Tab>
|
||||
@ -157,6 +158,7 @@ const MarketBottomPanel = memo(
|
||||
<TradingViews.Orders
|
||||
marketId={marketId}
|
||||
onMarketClick={onMarketClick}
|
||||
enforceBottomPlaceholder
|
||||
/>
|
||||
</VegaWalletContainer>
|
||||
</Tab>
|
||||
|
@ -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}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
@ -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();
|
||||
});
|
||||
});
|
||||
|
@ -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<AgGridReact | null>(null);
|
||||
const scrolledToTop = useRef(true);
|
||||
const [dataCount, setDataCount] = useState(0);
|
||||
const scrolledToTop = useRef(false);
|
||||
const [sort, setSort] = useState<Sort[] | undefined>();
|
||||
const [filter, setFilter] = useState<Filter | undefined>(initialFilter);
|
||||
const [editOrder, setEditOrder] = useState<Order | null>(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<Order>({
|
||||
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<Order>({
|
||||
gridRef,
|
||||
});
|
||||
const extractedData =
|
||||
data && !loading
|
||||
? data
|
||||
.filter((item) => item !== null)
|
||||
.map((item) => (item as OrderEdge).node)
|
||||
: null;
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="h-full relative">
|
||||
<OrderListTable
|
||||
rowData={extractedData}
|
||||
ref={gridRef}
|
||||
rowModelType="infinite"
|
||||
onGridReady={onGridReady}
|
||||
onBodyScrollEnd={onBodyScrollEnd}
|
||||
onBodyScroll={onBodyScroll}
|
||||
onFilterChanged={onFilterChanged}
|
||||
onSortChanged={onSortChange}
|
||||
cancel={cancel}
|
||||
@ -209,9 +175,7 @@ export const OrderListManager = ({
|
||||
blockLoadDebounceMillis={100}
|
||||
suppressLoadingOverlay
|
||||
suppressNoRowsOverlay
|
||||
isFullWidthRow={isFullWidthRow}
|
||||
fullWidthCellRenderer={fullWidthCellRenderer}
|
||||
rowClassRules={rowClassRules}
|
||||
{...bottomPlaceholderProps}
|
||||
/>
|
||||
<div className="pointer-events-none absolute inset-0">
|
||||
<AsyncRenderer
|
||||
@ -219,7 +183,7 @@ export const OrderListManager = ({
|
||||
error={error}
|
||||
data={data}
|
||||
noDataMessage={t('No orders')}
|
||||
noDataCondition={(data) => !(data && data.length)}
|
||||
noDataCondition={(data) => !dataCount}
|
||||
reload={reload}
|
||||
/>
|
||||
</div>
|
||||
|
@ -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]
|
||||
);
|
||||
|
@ -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 () => {
|
||||
|
@ -39,10 +39,10 @@ export const OrderListTable = memo(
|
||||
return (
|
||||
<AgGrid
|
||||
ref={ref}
|
||||
overlayNoRowsTemplate={t('No orders')}
|
||||
defaultColDef={{
|
||||
flex: 1,
|
||||
resizable: true,
|
||||
sortable: true,
|
||||
filterParams: { buttons: ['reset'] },
|
||||
}}
|
||||
style={{
|
||||
@ -74,6 +74,7 @@ export const OrderListTable = memo(
|
||||
value
|
||||
)
|
||||
}
|
||||
minWidth={150}
|
||||
/>
|
||||
<AgGridColumn
|
||||
headerName={t('Size')}
|
||||
@ -89,7 +90,6 @@ export const OrderListTable = memo(
|
||||
valueFormatter={({
|
||||
value,
|
||||
data,
|
||||
node,
|
||||
}: VegaValueFormatterParams<Order, 'size'>) => {
|
||||
if (!data) {
|
||||
return undefined;
|
||||
@ -110,6 +110,7 @@ export const OrderListTable = memo(
|
||||
)
|
||||
);
|
||||
}}
|
||||
minWidth={80}
|
||||
/>
|
||||
<AgGridColumn
|
||||
field="type"
|
||||
@ -120,7 +121,6 @@ export const OrderListTable = memo(
|
||||
valueFormatter={({
|
||||
data: order,
|
||||
value,
|
||||
node,
|
||||
}: VegaValueFormatterParams<Order, 'type'>) => {
|
||||
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}
|
||||
/>
|
||||
<AgGridColumn
|
||||
field="status"
|
||||
@ -160,6 +161,7 @@ export const OrderListTable = memo(
|
||||
{valueFormatted}
|
||||
</span>
|
||||
)}
|
||||
minWidth={100}
|
||||
/>
|
||||
<AgGridColumn
|
||||
headerName={t('Filled')}
|
||||
@ -186,6 +188,7 @@ export const OrderListTable = memo(
|
||||
dps
|
||||
)}/${addDecimalsFormatNumber(size.toString(), dps)}`;
|
||||
}}
|
||||
minWidth={100}
|
||||
/>
|
||||
<AgGridColumn
|
||||
field="price"
|
||||
@ -208,6 +211,7 @@ export const OrderListTable = memo(
|
||||
}
|
||||
return addDecimalsFormatNumber(value, data.market.decimalPlaces);
|
||||
}}
|
||||
minWidth={100}
|
||||
/>
|
||||
<AgGridColumn
|
||||
field="timeInForce"
|
||||
@ -231,6 +235,7 @@ export const OrderListTable = memo(
|
||||
|
||||
return value ? Schema.OrderTimeInForceMapping[value] : '';
|
||||
}}
|
||||
minWidth={150}
|
||||
/>
|
||||
<AgGridColumn
|
||||
field="createdAt"
|
||||
@ -244,6 +249,7 @@ export const OrderListTable = memo(
|
||||
</span>
|
||||
);
|
||||
}}
|
||||
minWidth={150}
|
||||
/>
|
||||
<AgGridColumn
|
||||
field="updatedAt"
|
||||
@ -261,6 +267,7 @@ export const OrderListTable = memo(
|
||||
</span>
|
||||
);
|
||||
}}
|
||||
minWidth={150}
|
||||
/>
|
||||
<AgGridColumn
|
||||
colId="amend"
|
||||
@ -284,6 +291,7 @@ export const OrderListTable = memo(
|
||||
</>
|
||||
) : null;
|
||||
}}
|
||||
sortable={false}
|
||||
/>
|
||||
</AgGrid>
|
||||
);
|
||||
|
@ -68,7 +68,7 @@ export const useBottomPlaceholder = <T extends {}>({
|
||||
isFullWidthRow,
|
||||
fullWidthCellRenderer,
|
||||
onSortChanged: onRowsChanged,
|
||||
onFilterChange: onRowsChanged,
|
||||
onFilterChanged: onRowsChanged,
|
||||
}
|
||||
: {},
|
||||
[onBodyScrollEnd, onRowsChanged, disabled]
|
||||
|
@ -258,7 +258,16 @@ function makeDataProviderInternal<
|
||||
client
|
||||
.query<QueryData>({
|
||||
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',
|
||||
|
Loading…
Reference in New Issue
Block a user