chore(trading): add filters to the proposals table (#3375)

This commit is contained in:
Maciek 2023-04-06 15:30:21 +02:00 committed by GitHub
parent 643d5408cd
commit 7e4aafcb77
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 162 additions and 22 deletions

View File

@ -1,5 +1,5 @@
import * as Schema from '@vegaprotocol/types';
import { aliasGQLQuery } from '@vegaprotocol/cypress';
import { aliasGQLQuery, checkSorting } from '@vegaprotocol/cypress';
import { marketsQuery } from '@vegaprotocol/mock';
import { getDateTimeFormat } from '@vegaprotocol/utils';
@ -85,6 +85,7 @@ describe('markets table', { tags: '@smoke' }, () => {
cy.getByTestId('view-market-list-link')
.should('have.attr', 'href', '#/markets/all')
.click();
cy.get('[data-testid="All markets"]').should(
'have.attr',
'data-state',
@ -117,6 +118,85 @@ describe('markets table', { tags: '@smoke' }, () => {
`${Cypress.env('VEGA_TOKEN_URL')}/proposals/propose/new-market`
);
});
it('proposed markets tab should be sorted properly', () => {
cy.getByTestId('view-market-list-link').click();
cy.get('[data-testid="Proposed markets"]').click();
const marketColDefault = [
'ETHUSD',
'LINKUSD',
'ETHUSD',
'ETHDAI.MF21',
'AAPL.MF21',
'BTCUSD.MF21',
'TSLA.QM21',
'AAVEDAI.MF21',
'ETHBTC.QM21',
'UNIDAI.MF21',
];
const marketColAsc = [
'AAPL.MF21',
'AAVEDAI.MF21',
'BTCUSD.MF21',
'ETHBTC.QM21',
'ETHDAI.MF21',
'ETHUSD',
'ETHUSD',
'LINKUSD',
'TSLA.QM21',
'UNIDAI.MF21',
];
const marketColDesc = [
'UNIDAI.MF21',
'TSLA.QM21',
'LINKUSD',
'ETHUSD',
'ETHUSD',
'ETHDAI.MF21',
'ETHBTC.QM21',
'BTCUSD.MF21',
'AAVEDAI.MF21',
'AAPL.MF21',
];
checkSorting('market', marketColDefault, marketColAsc, marketColDesc);
const stateColDefault = [
'Open',
'Passed',
'Waiting for Node Vote',
'Open',
'Passed',
'Open',
'Passed',
'Open',
'Waiting for Node Vote',
'Open',
];
const stateColAsc = [
'Open',
'Open',
'Open',
'Open',
'Open',
'Passed',
'Passed',
'Passed',
'Waiting for Node Vote',
'Waiting for Node Vote',
];
const stateColDesc = [
'Waiting for Node Vote',
'Waiting for Node Vote',
'Passed',
'Passed',
'Passed',
'Open',
'Open',
'Open',
'Open',
'Open',
];
checkSorting('state', stateColDefault, stateColAsc, stateColDesc);
});
it('opening auction subsets should be properly displayed', () => {
cy.mockTradingPage(

View File

@ -52,6 +52,9 @@ export const checkSorting = (
cy.get(`[col-id="${column}"]`).click();
});
checkSortChange(orderTabDesc, column);
cy.get('.ag-header-container').within(() => {
cy.get(`[col-id="${column}"]`).click();
});
};
const checkSortChange = (tabsArr: string[], column: string) => {

View File

@ -11,12 +11,13 @@ import {
AgGridDynamic as AgGrid,
PriceFlashCell,
MarketNameCell,
SetFilter,
} from '@vegaprotocol/datagrid';
import { ButtonLink } from '@vegaprotocol/ui-toolkit';
import { AgGridColumn } from 'ag-grid-react';
import type { AgGridReact } from 'ag-grid-react';
import * as Schema from '@vegaprotocol/types';
import type { MarketMaybeWithData, MarketFieldsFragment } from '../../';
import type { MarketMaybeWithData } from '../../';
import { useAssetDetailsDialogStore } from '@vegaprotocol/assets';
const { MarketTradingMode, AuctionTrigger } = Schema;
@ -33,7 +34,6 @@ export const MarketListTable = forwardRef<
return (
<AgGrid
style={{ width: '100%', height: '100%' }}
overlayNoRowsTemplate={t('No markets')}
getRowId={getRowId}
ref={ref}
defaultColDef={{
@ -43,7 +43,7 @@ export const MarketListTable = forwardRef<
filter: true,
filterParams: { buttons: ['reset'] },
}}
suppressCellFocus={true}
suppressCellFocus
components={{ PriceFlashCell, MarketNameCell }}
{...props}
>
@ -59,11 +59,11 @@ export const MarketListTable = forwardRef<
/>
<AgGridColumn
headerName={t('Trading mode')}
field="data"
field="tradingMode"
minWidth={170}
valueGetter={({
valueFormatter={({
data,
}: VegaValueGetterParams<MarketMaybeWithData, 'data'>) => {
}: VegaValueFormatterParams<MarketMaybeWithData, 'data'>) => {
if (!data?.data) return undefined;
const { trigger } = data.data;
const { tradingMode } = data;
@ -75,14 +75,22 @@ export const MarketListTable = forwardRef<
- ${Schema.AuctionTriggerMapping[trigger]}`
: Schema.MarketTradingModeMapping[tradingMode];
}}
filter={SetFilter}
filterParams={{
set: Schema.MarketTradingModeMapping,
}}
/>
<AgGridColumn
headerName={t('Status')}
field="state"
valueGetter={({
valueFormatter={({
data,
}: VegaValueGetterParams<MarketFieldsFragment, 'state'>) => {
return data?.state ? Schema.MarketStateMapping[data?.state] : '-';
}: VegaValueFormatterParams<MarketMaybeWithData, 'state'>) => {
return data?.state ? Schema.MarketStateMapping[data.state] : '-';
}}
filter={SetFilter}
filterParams={{
set: Schema.MarketStateMapping,
}}
/>
<AgGridColumn

View File

@ -1,4 +1,6 @@
import type { MouseEvent } from 'react';
import { useCallback, useEffect, useRef, useState } from 'react';
import type { AgGridReact } from 'ag-grid-react';
import { t } from '@vegaprotocol/i18n';
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
import { MarketListTable } from './market-list-table';
@ -12,15 +14,24 @@ interface MarketsContainerProps {
}
export const MarketsContainer = ({ onSelect }: MarketsContainerProps) => {
const gridRef = useRef<AgGridReact | null>(null);
const [dataCount, setDataCount] = useState(0);
const { data, error, loading, reload } = useDataProvider({
dataProvider,
skipUpdates: true,
variables: undefined,
});
useEffect(() => {
setDataCount(gridRef.current?.api?.getModel().getRowCount() ?? 0);
}, [data]);
const onFilterChanged = useCallback(() => {
setDataCount(gridRef.current?.api?.getModel().getRowCount() ?? 0);
}, []);
return (
<div className="h-full relative">
<MarketListTable
rowData={error ? [] : data}
ref={gridRef}
rowData={data}
suppressLoadingOverlay
suppressNoRowsOverlay
onCellClicked={(cellEvent: CellClickedEvent) => {
@ -40,6 +51,7 @@ export const MarketsContainer = ({ onSelect }: MarketsContainerProps) => {
);
}}
onMarketClick={onSelect}
onFilterChanged={onFilterChanged}
/>
<div className="pointer-events-none absolute inset-0">
<AsyncRenderer
@ -47,6 +59,7 @@ export const MarketsContainer = ({ onSelect }: MarketsContainerProps) => {
error={error}
data={data}
noDataMessage={t('No markets')}
noDataCondition={() => !dataCount}
reload={reload}
/>
</div>

View File

@ -91,6 +91,6 @@ describe('ProposalsList', () => {
await waitFor(() => {
expect(container).toBeInTheDocument();
});
expect(screen.getByText('No Rows To Show')).toBeInTheDocument();
expect(screen.getByText('No markets')).toBeInTheDocument();
});
});

View File

@ -1,13 +1,21 @@
import { useCallback, useEffect, useRef, useState } from 'react';
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
import { AgGridDynamic as AgGrid } from '@vegaprotocol/datagrid';
import { useDataProvider } from '@vegaprotocol/react-helpers';
import { t } from '@vegaprotocol/i18n';
import * as Types from '@vegaprotocol/types';
import { proposalsDataProvider } from '../proposals-data-provider';
import { useCallback, useRef } from 'react';
import type { AgGridReact } from 'ag-grid-react';
import { useColumnDefs } from './use-column-defs';
import type { ProposalListFieldsFragment } from '../proposals-data-provider/__generated__/Proposals';
// prevent cutting filter windows by auto-height layout
const CUSTOM_GRID_STYLES = `
.ag-layout-auto-height {
min-height: 200px !important;
}
`;
export const getNewMarketProposals = (data: ProposalListFieldsFragment[]) =>
data.filter((proposal) =>
[
@ -19,6 +27,7 @@ export const getNewMarketProposals = (data: ProposalListFieldsFragment[]) =>
export const ProposalsList = () => {
const gridRef = useRef<AgGridReact | null>(null);
const [dataCount, setDataCount] = useState(0);
const handleOnGridReady = useCallback(() => {
gridRef.current?.api?.sizeColumnsToFit();
}, [gridRef]);
@ -30,22 +39,37 @@ export const ProposalsList = () => {
});
const filteredData = getNewMarketProposals(data || []);
const { columnDefs, defaultColDef } = useColumnDefs();
useEffect(() => {
setDataCount(gridRef.current?.api?.getModel().getRowCount() ?? 0);
}, [filteredData]);
const onFilterChanged = useCallback(() => {
setDataCount(gridRef.current?.api?.getModel().getRowCount() ?? 0);
}, []);
return (
<AsyncRenderer
loading={loading}
error={error}
data={filteredData}
reload={reload}
>
<div className="relative">
<AgGrid
ref={gridRef}
className="w-full h-full"
domLayout="autoHeight"
className="min-w-full"
columnDefs={columnDefs}
rowData={filteredData}
defaultColDef={defaultColDef}
onGridReady={handleOnGridReady}
suppressLoadingOverlay
suppressNoRowsOverlay
onFilterChanged={onFilterChanged}
customThemeParams={CUSTOM_GRID_STYLES}
/>
</AsyncRenderer>
<div className="pointer-events-none absolute inset-0">
<AsyncRenderer
loading={loading}
error={error}
data={filteredData}
noDataMessage={t('No markets')}
noDataCondition={() => !dataCount}
reload={reload}
/>
</div>
</div>
);
};

View File

@ -1,6 +1,7 @@
import { useMemo } from 'react';
import BigNumber from 'bignumber.js';
import type { ColDef } from 'ag-grid-community';
import { DateRangeFilter, SetFilter } from '@vegaprotocol/datagrid';
import { useEnvironment } from '@vegaprotocol/environment';
import { getDateTimeFormat } from '@vegaprotocol/utils';
import { t } from '@vegaprotocol/i18n';
@ -73,6 +74,10 @@ export const useColumnDefs = () => {
value,
}: VegaValueFormatterParams<ProposalListFieldsFragment, 'state'>) =>
value ? ProposalStateMapping[value] : '-',
filter: SetFilter,
filterParams: {
set: ProposalStateMapping,
},
},
{
colId: 'voting',
@ -99,6 +104,7 @@ export const useColumnDefs = () => {
}
return '-';
},
filter: false,
},
{
colId: 'closing-date',
@ -110,6 +116,7 @@ export const useColumnDefs = () => {
ProposalListFieldsFragment,
'terms.closingDatetime'
>) => (value ? getDateTimeFormat().format(new Date(value)) : '-'),
filter: DateRangeFilter,
},
{
colId: 'enactment-date',
@ -121,13 +128,18 @@ export const useColumnDefs = () => {
ProposalListFieldsFragment,
'terms.enactmentDatetime'
>) => (value ? getDateTimeFormat().format(new Date(value)) : '-'),
filter: DateRangeFilter,
},
];
}, [VEGA_TOKEN_URL, requiredMajorityPercentage]);
const defaultColDef: ColDef = useMemo(() => {
return {
sortable: false,
sortable: true,
cellClass: cellCss,
flex: 1,
resizable: true,
filter: true,
filterParams: { buttons: ['reset'] },
};
}, []);
return useMemo(