chore(orders): remove infinite scroll from order table (#3247)

Co-authored-by: Matthew Russell <mattrussell36@gmail.com>
This commit is contained in:
Maciek 2023-03-23 09:13:07 +01:00 committed by GitHub
parent b611d30b31
commit f649d78565
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 108 additions and 83 deletions

View File

@ -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}']`)

View File

@ -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>

View File

@ -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}
/>
);
};

View File

@ -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();
});
});

View File

@ -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>

View File

@ -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]
);

View File

@ -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 () => {

View File

@ -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>
);

View File

@ -68,7 +68,7 @@ export const useBottomPlaceholder = <T extends {}>({
isFullWidthRow,
fullWidthCellRenderer,
onSortChanged: onRowsChanged,
onFilterChange: onRowsChanged,
onFilterChanged: onRowsChanged,
}
: {},
[onBodyScrollEnd, onRowsChanged, disabled]

View File

@ -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',