From ff2e2574f666c413cfd4714f91e9cf18711d584b Mon Sep 17 00:00:00 2001 From: Maciek Date: Thu, 28 Sep 2023 21:14:32 +0200 Subject: [PATCH] chore(trading): add handle of autosizing selected columns - main branch (#4888) --- .../src/integration/trading-orders.cy.ts | 7 +-- .../orders-container/orders-container.tsx | 12 +++- .../positions-container.tsx | 8 ++- .../src/lib/use-datagrid-events.spec.tsx | 63 ++++++++++++------- libs/datagrid/src/lib/use-datagrid-events.ts | 17 ++++- .../lib/components/order-list/order-list.tsx | 1 + 6 files changed, 76 insertions(+), 32 deletions(-) diff --git a/apps/trading-e2e/src/integration/trading-orders.cy.ts b/apps/trading-e2e/src/integration/trading-orders.cy.ts index c595f5aab..ae79c684c 100644 --- a/apps/trading-e2e/src/integration/trading-orders.cy.ts +++ b/apps/trading-e2e/src/integration/trading-orders.cy.ts @@ -9,7 +9,7 @@ import { testOrderAmendment, } from '../support/order-validation'; -const orderSymbol = 'market.tradableInstrument.instrument.code'; +const orderSymbol = 'instrument-code'; const orderSize = 'size'; const orderType = 'type'; const orderStatus = 'status'; @@ -229,10 +229,7 @@ describe('subscribe orders', { tags: '@smoke' }, () => { status: Schema.OrderStatus.STATUS_FILLED, }); cy.getByTestId(`order-status-${orderId}`).should('have.text', 'Filled'); - cy.get('[col-id="market.tradableInstrument.instrument.code"]').contains( - '[title="Future"]', - 'Futr' - ); + cy.get(`[col-id="${orderSymbol}"]`).contains('[title="Future"]', 'Futr'); }); it('must see a rejected order', () => { diff --git a/apps/trading/components/orders-container/orders-container.tsx b/apps/trading/components/orders-container/orders-container.tsx index c67979964..3f8d7a14b 100644 --- a/apps/trading/components/orders-container/orders-container.tsx +++ b/apps/trading/components/orders-container/orders-container.tsx @@ -28,14 +28,20 @@ export interface OrderContainerProps { filter?: Filter; } +const AUTO_SIZE_COLUMNS = ['instrument-code']; + export const OrdersContainer = ({ filter }: OrderContainerProps) => { const { pubKey, isReadOnly } = useVegaWallet(); const onMarketClick = useMarketClickHandler(true); const onOrderTypeClick = useMarketLiquidityClickHandler(); const { gridState, updateGridState } = useOrderListGridState(filter); - const gridStoreCallbacks = useDataGridEvents(gridState, (newState) => { - updateGridState(filter, newState); - }); + const gridStoreCallbacks = useDataGridEvents( + gridState, + (newState) => { + updateGridState(filter, newState); + }, + AUTO_SIZE_COLUMNS + ); if (!pubKey) { return {t('Please connect Vega wallet')}; diff --git a/apps/trading/components/positions-container/positions-container.tsx b/apps/trading/components/positions-container/positions-container.tsx index f830d4666..295fb9463 100644 --- a/apps/trading/components/positions-container/positions-container.tsx +++ b/apps/trading/components/positions-container/positions-container.tsx @@ -10,6 +10,8 @@ import { create } from 'zustand'; import { persist } from 'zustand/middleware'; import { useMarketClickHandler } from '../../lib/hooks/use-market-click-handler'; +const AUTO_SIZE_COLUMNS = ['marketCode']; + export const PositionsContainer = ({ allKeys }: { allKeys?: boolean }) => { const onMarketClick = useMarketClickHandler(true); const { pubKey, pubKeys, isReadOnly } = useVegaWallet(); @@ -17,7 +19,11 @@ export const PositionsContainer = ({ allKeys }: { allKeys?: boolean }) => { const showClosed = usePositionsStore((store) => store.showClosedMarkets); const gridStore = usePositionsStore((store) => store.gridStore); const updateGridStore = usePositionsStore((store) => store.updateGridStore); - const gridStoreCallbacks = useDataGridEvents(gridStore, updateGridStore); + const gridStoreCallbacks = useDataGridEvents( + gridStore, + updateGridStore, + AUTO_SIZE_COLUMNS + ); if (!pubKey) { return ( diff --git a/libs/datagrid/src/lib/use-datagrid-events.spec.tsx b/libs/datagrid/src/lib/use-datagrid-events.spec.tsx index 486a2f3b7..fb2a51aa0 100644 --- a/libs/datagrid/src/lib/use-datagrid-events.spec.tsx +++ b/libs/datagrid/src/lib/use-datagrid-events.spec.tsx @@ -5,8 +5,6 @@ import type { MutableRefObject } from 'react'; import { useRef } from 'react'; import type { AgGridReact } from 'ag-grid-react'; -const GRID_EVENT_DEBOUNCE_TIME = 500; - const gridProps = { rowData: [{ id: 1 }], columnDefs: [ @@ -18,25 +16,29 @@ const gridProps = { ], style: { width: 500, height: 300 }, }; +const GRID_EVENT_DEBOUNCE_TIME = 300; +let gridRef: MutableRefObject; +function TestComponent({ + hookParams, +}: { + hookParams: Parameters; +}) { + const hookCallbacks = useDataGridEvents(...hookParams); + gridRef = useRef(null); + return ; +} // Not using render hook so I can pass event callbacks // to a rendered grid function setup(...args: Parameters) { - let gridRef; - - function TestComponent() { - const hookCallbacks = useDataGridEvents(...args); - gridRef = useRef(null); - return ; - } - render(); - return gridRef as unknown as MutableRefObject; + return render(); } describe('useDataGridEvents', () => { const originalWarn = console.warn; beforeAll(() => { + gridRef = undefined; jest.useFakeTimers(); // disabling some ag grid warnings that are caused by test setup only @@ -55,15 +57,15 @@ describe('useDataGridEvents', () => { columnState: undefined, }; - const result = setup(initialState, callback); + setup(initialState, callback); // column state was not updated, so the default width provided by the // col def should be set - expect(result.current.columnApi.getColumnState()[0].width).toEqual( + expect(gridRef.current?.columnApi.getColumnState()[0].width).toEqual( gridProps.columnDefs[0].width ); // no filters set - expect(result.current.api.getFilterModel()).toEqual({}); + expect(gridRef.current?.api.getFilterModel()).toEqual({}); // Set filter const idFilter = { @@ -72,7 +74,7 @@ describe('useDataGridEvents', () => { type: 'equals', }; await act(async () => { - result.current.api.setFilterModel({ + gridRef.current?.api.setFilterModel({ id: idFilter, }); }); @@ -88,7 +90,7 @@ describe('useDataGridEvents', () => { }, }); callback.mockClear(); - expect(result.current.api.getFilterModel()['id']).toEqual(idFilter); + expect(gridRef.current?.api.getFilterModel()['id']).toEqual(idFilter); }); it('applies grid state on ready', async () => { @@ -105,11 +107,11 @@ describe('useDataGridEvents', () => { columnState: [colState], }; - const result = setup(initialState, jest.fn()); + setup(initialState, jest.fn()); await waitFor(() => { - expect(result.current.api.getFilterModel()['id']).toEqual(idFilter); - expect(result.current.columnApi.getColumnState()[0]).toEqual( + expect(gridRef.current?.api.getFilterModel()['id']).toEqual(idFilter); + expect(gridRef.current?.columnApi.getColumnState()[0]).toEqual( expect.objectContaining(colState) ); }); @@ -122,13 +124,13 @@ describe('useDataGridEvents', () => { columnState: undefined, }; - const result = setup(initialState, callback); + setup(initialState, callback); const newWidth = 400; // Set col width multiple times await act(async () => { - result.current.columnApi.setColumnWidth('id', newWidth); + gridRef.current?.columnApi.setColumnWidth('id', newWidth); }); expect(callback).not.toHaveBeenCalled(); @@ -139,4 +141,23 @@ describe('useDataGridEvents', () => { expect(callback).toHaveBeenCalledTimes(0); }); + + it('columns for autosizing should be handle', () => { + const callback = jest.fn(); + const initialState = { + filterModel: undefined, + columnState: undefined, + }; + + const { rerender } = setup(initialState, callback, ['id']); + jest.spyOn(gridRef.current?.columnApi, 'autoSizeColumns'); + rerender(); + act(() => { + gridRef.current?.api.setRowData([{ id: 'test-id' }]); + jest.advanceTimersByTime(GRID_EVENT_DEBOUNCE_TIME); + }); + expect(gridRef.current?.columnApi.autoSizeColumns).toHaveBeenCalledWith([ + 'id', + ]); + }); }); diff --git a/libs/datagrid/src/lib/use-datagrid-events.ts b/libs/datagrid/src/lib/use-datagrid-events.ts index 23aaf68e1..70a850be0 100644 --- a/libs/datagrid/src/lib/use-datagrid-events.ts +++ b/libs/datagrid/src/lib/use-datagrid-events.ts @@ -6,6 +6,7 @@ import type { FilterChangedEvent, FirstDataRenderedEvent, SortChangedEvent, + GridReadyEvent, } from 'ag-grid-community'; import { useCallback } from 'react'; @@ -17,7 +18,8 @@ type State = { export const useDataGridEvents = ( state: State, - callback: (data: State) => void + callback: (data: State) => void, + autoSizeColumns?: string[] ) => { /** * Callback for filter events @@ -78,7 +80,7 @@ export const useDataGridEvents = ( * State only applied if found, otherwise columns sized to fit available space */ const onGridReady = useCallback( - ({ api, columnApi }: FirstDataRenderedEvent) => { + ({ api, columnApi }: GridReadyEvent) => { if (!api || !columnApi) return; if (state.columnState) { @@ -97,6 +99,16 @@ export const useDataGridEvents = ( [state] ); + const onFirstDataRendered = useCallback( + ({ columnApi }: FirstDataRenderedEvent) => { + if (!columnApi) return; + if (!state?.columnState && autoSizeColumns?.length) { + columnApi.autoSizeColumns(autoSizeColumns); + } + }, + [state, autoSizeColumns] + ); + return { onGridReady, // these events don't use the 'finished' flag @@ -106,5 +118,6 @@ export const useDataGridEvents = ( // these trigger a lot so this callback uses the 'finished' flag onColumnMoved: onDebouncedColumnChange, onColumnResized: onDebouncedColumnChange, + onFirstDataRendered, }; }; 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 7bba17e75..719e981d0 100644 --- a/libs/orders/src/lib/components/order-list/order-list.tsx +++ b/libs/orders/src/lib/components/order-list/order-list.tsx @@ -79,6 +79,7 @@ export const OrderListTable = memo< () => [ { headerName: t('Market'), + colId: 'instrument-code', field: 'market.tradableInstrument.instrument.code', cellRenderer: 'MarketNameCell', cellRendererParams: { idPath: 'market.id', onMarketClick },