chore(trading): add filters to the proposals table (#3375)
This commit is contained in:
parent
643d5408cd
commit
7e4aafcb77
@ -1,5 +1,5 @@
|
|||||||
import * as Schema from '@vegaprotocol/types';
|
import * as Schema from '@vegaprotocol/types';
|
||||||
import { aliasGQLQuery } from '@vegaprotocol/cypress';
|
import { aliasGQLQuery, checkSorting } from '@vegaprotocol/cypress';
|
||||||
import { marketsQuery } from '@vegaprotocol/mock';
|
import { marketsQuery } from '@vegaprotocol/mock';
|
||||||
import { getDateTimeFormat } from '@vegaprotocol/utils';
|
import { getDateTimeFormat } from '@vegaprotocol/utils';
|
||||||
|
|
||||||
@ -85,6 +85,7 @@ describe('markets table', { tags: '@smoke' }, () => {
|
|||||||
cy.getByTestId('view-market-list-link')
|
cy.getByTestId('view-market-list-link')
|
||||||
.should('have.attr', 'href', '#/markets/all')
|
.should('have.attr', 'href', '#/markets/all')
|
||||||
.click();
|
.click();
|
||||||
|
|
||||||
cy.get('[data-testid="All markets"]').should(
|
cy.get('[data-testid="All markets"]').should(
|
||||||
'have.attr',
|
'have.attr',
|
||||||
'data-state',
|
'data-state',
|
||||||
@ -117,6 +118,85 @@ describe('markets table', { tags: '@smoke' }, () => {
|
|||||||
`${Cypress.env('VEGA_TOKEN_URL')}/proposals/propose/new-market`
|
`${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', () => {
|
it('opening auction subsets should be properly displayed', () => {
|
||||||
cy.mockTradingPage(
|
cy.mockTradingPage(
|
||||||
|
@ -52,6 +52,9 @@ export const checkSorting = (
|
|||||||
cy.get(`[col-id="${column}"]`).click();
|
cy.get(`[col-id="${column}"]`).click();
|
||||||
});
|
});
|
||||||
checkSortChange(orderTabDesc, column);
|
checkSortChange(orderTabDesc, column);
|
||||||
|
cy.get('.ag-header-container').within(() => {
|
||||||
|
cy.get(`[col-id="${column}"]`).click();
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const checkSortChange = (tabsArr: string[], column: string) => {
|
const checkSortChange = (tabsArr: string[], column: string) => {
|
||||||
|
@ -11,12 +11,13 @@ import {
|
|||||||
AgGridDynamic as AgGrid,
|
AgGridDynamic as AgGrid,
|
||||||
PriceFlashCell,
|
PriceFlashCell,
|
||||||
MarketNameCell,
|
MarketNameCell,
|
||||||
|
SetFilter,
|
||||||
} from '@vegaprotocol/datagrid';
|
} from '@vegaprotocol/datagrid';
|
||||||
import { ButtonLink } from '@vegaprotocol/ui-toolkit';
|
import { ButtonLink } from '@vegaprotocol/ui-toolkit';
|
||||||
import { AgGridColumn } from 'ag-grid-react';
|
import { AgGridColumn } from 'ag-grid-react';
|
||||||
import type { AgGridReact } from 'ag-grid-react';
|
import type { AgGridReact } from 'ag-grid-react';
|
||||||
import * as Schema from '@vegaprotocol/types';
|
import * as Schema from '@vegaprotocol/types';
|
||||||
import type { MarketMaybeWithData, MarketFieldsFragment } from '../../';
|
import type { MarketMaybeWithData } from '../../';
|
||||||
import { useAssetDetailsDialogStore } from '@vegaprotocol/assets';
|
import { useAssetDetailsDialogStore } from '@vegaprotocol/assets';
|
||||||
|
|
||||||
const { MarketTradingMode, AuctionTrigger } = Schema;
|
const { MarketTradingMode, AuctionTrigger } = Schema;
|
||||||
@ -33,7 +34,6 @@ export const MarketListTable = forwardRef<
|
|||||||
return (
|
return (
|
||||||
<AgGrid
|
<AgGrid
|
||||||
style={{ width: '100%', height: '100%' }}
|
style={{ width: '100%', height: '100%' }}
|
||||||
overlayNoRowsTemplate={t('No markets')}
|
|
||||||
getRowId={getRowId}
|
getRowId={getRowId}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
defaultColDef={{
|
defaultColDef={{
|
||||||
@ -43,7 +43,7 @@ export const MarketListTable = forwardRef<
|
|||||||
filter: true,
|
filter: true,
|
||||||
filterParams: { buttons: ['reset'] },
|
filterParams: { buttons: ['reset'] },
|
||||||
}}
|
}}
|
||||||
suppressCellFocus={true}
|
suppressCellFocus
|
||||||
components={{ PriceFlashCell, MarketNameCell }}
|
components={{ PriceFlashCell, MarketNameCell }}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
@ -59,11 +59,11 @@ export const MarketListTable = forwardRef<
|
|||||||
/>
|
/>
|
||||||
<AgGridColumn
|
<AgGridColumn
|
||||||
headerName={t('Trading mode')}
|
headerName={t('Trading mode')}
|
||||||
field="data"
|
field="tradingMode"
|
||||||
minWidth={170}
|
minWidth={170}
|
||||||
valueGetter={({
|
valueFormatter={({
|
||||||
data,
|
data,
|
||||||
}: VegaValueGetterParams<MarketMaybeWithData, 'data'>) => {
|
}: VegaValueFormatterParams<MarketMaybeWithData, 'data'>) => {
|
||||||
if (!data?.data) return undefined;
|
if (!data?.data) return undefined;
|
||||||
const { trigger } = data.data;
|
const { trigger } = data.data;
|
||||||
const { tradingMode } = data;
|
const { tradingMode } = data;
|
||||||
@ -75,14 +75,22 @@ export const MarketListTable = forwardRef<
|
|||||||
- ${Schema.AuctionTriggerMapping[trigger]}`
|
- ${Schema.AuctionTriggerMapping[trigger]}`
|
||||||
: Schema.MarketTradingModeMapping[tradingMode];
|
: Schema.MarketTradingModeMapping[tradingMode];
|
||||||
}}
|
}}
|
||||||
|
filter={SetFilter}
|
||||||
|
filterParams={{
|
||||||
|
set: Schema.MarketTradingModeMapping,
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
<AgGridColumn
|
<AgGridColumn
|
||||||
headerName={t('Status')}
|
headerName={t('Status')}
|
||||||
field="state"
|
field="state"
|
||||||
valueGetter={({
|
valueFormatter={({
|
||||||
data,
|
data,
|
||||||
}: VegaValueGetterParams<MarketFieldsFragment, 'state'>) => {
|
}: VegaValueFormatterParams<MarketMaybeWithData, 'state'>) => {
|
||||||
return data?.state ? Schema.MarketStateMapping[data?.state] : '-';
|
return data?.state ? Schema.MarketStateMapping[data.state] : '-';
|
||||||
|
}}
|
||||||
|
filter={SetFilter}
|
||||||
|
filterParams={{
|
||||||
|
set: Schema.MarketStateMapping,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<AgGridColumn
|
<AgGridColumn
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
import type { MouseEvent } from 'react';
|
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 { t } from '@vegaprotocol/i18n';
|
||||||
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
|
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
|
||||||
import { MarketListTable } from './market-list-table';
|
import { MarketListTable } from './market-list-table';
|
||||||
@ -12,15 +14,24 @@ interface MarketsContainerProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const MarketsContainer = ({ onSelect }: MarketsContainerProps) => {
|
export const MarketsContainer = ({ onSelect }: MarketsContainerProps) => {
|
||||||
|
const gridRef = useRef<AgGridReact | null>(null);
|
||||||
|
const [dataCount, setDataCount] = useState(0);
|
||||||
const { data, error, loading, reload } = useDataProvider({
|
const { data, error, loading, reload } = useDataProvider({
|
||||||
dataProvider,
|
dataProvider,
|
||||||
skipUpdates: true,
|
skipUpdates: true,
|
||||||
variables: undefined,
|
variables: undefined,
|
||||||
});
|
});
|
||||||
|
useEffect(() => {
|
||||||
|
setDataCount(gridRef.current?.api?.getModel().getRowCount() ?? 0);
|
||||||
|
}, [data]);
|
||||||
|
const onFilterChanged = useCallback(() => {
|
||||||
|
setDataCount(gridRef.current?.api?.getModel().getRowCount() ?? 0);
|
||||||
|
}, []);
|
||||||
return (
|
return (
|
||||||
<div className="h-full relative">
|
<div className="h-full relative">
|
||||||
<MarketListTable
|
<MarketListTable
|
||||||
rowData={error ? [] : data}
|
ref={gridRef}
|
||||||
|
rowData={data}
|
||||||
suppressLoadingOverlay
|
suppressLoadingOverlay
|
||||||
suppressNoRowsOverlay
|
suppressNoRowsOverlay
|
||||||
onCellClicked={(cellEvent: CellClickedEvent) => {
|
onCellClicked={(cellEvent: CellClickedEvent) => {
|
||||||
@ -40,6 +51,7 @@ export const MarketsContainer = ({ onSelect }: MarketsContainerProps) => {
|
|||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
onMarketClick={onSelect}
|
onMarketClick={onSelect}
|
||||||
|
onFilterChanged={onFilterChanged}
|
||||||
/>
|
/>
|
||||||
<div className="pointer-events-none absolute inset-0">
|
<div className="pointer-events-none absolute inset-0">
|
||||||
<AsyncRenderer
|
<AsyncRenderer
|
||||||
@ -47,6 +59,7 @@ export const MarketsContainer = ({ onSelect }: MarketsContainerProps) => {
|
|||||||
error={error}
|
error={error}
|
||||||
data={data}
|
data={data}
|
||||||
noDataMessage={t('No markets')}
|
noDataMessage={t('No markets')}
|
||||||
|
noDataCondition={() => !dataCount}
|
||||||
reload={reload}
|
reload={reload}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -91,6 +91,6 @@ describe('ProposalsList', () => {
|
|||||||
await waitFor(() => {
|
await waitFor(() => {
|
||||||
expect(container).toBeInTheDocument();
|
expect(container).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
expect(screen.getByText('No Rows To Show')).toBeInTheDocument();
|
expect(screen.getByText('No markets')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,13 +1,21 @@
|
|||||||
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||||
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
|
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
|
||||||
import { AgGridDynamic as AgGrid } from '@vegaprotocol/datagrid';
|
import { AgGridDynamic as AgGrid } from '@vegaprotocol/datagrid';
|
||||||
import { useDataProvider } from '@vegaprotocol/react-helpers';
|
import { useDataProvider } from '@vegaprotocol/react-helpers';
|
||||||
|
import { t } from '@vegaprotocol/i18n';
|
||||||
import * as Types from '@vegaprotocol/types';
|
import * as Types from '@vegaprotocol/types';
|
||||||
import { proposalsDataProvider } from '../proposals-data-provider';
|
import { proposalsDataProvider } from '../proposals-data-provider';
|
||||||
import { useCallback, useRef } from 'react';
|
|
||||||
import type { AgGridReact } from 'ag-grid-react';
|
import type { AgGridReact } from 'ag-grid-react';
|
||||||
import { useColumnDefs } from './use-column-defs';
|
import { useColumnDefs } from './use-column-defs';
|
||||||
import type { ProposalListFieldsFragment } from '../proposals-data-provider/__generated__/Proposals';
|
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[]) =>
|
export const getNewMarketProposals = (data: ProposalListFieldsFragment[]) =>
|
||||||
data.filter((proposal) =>
|
data.filter((proposal) =>
|
||||||
[
|
[
|
||||||
@ -19,6 +27,7 @@ export const getNewMarketProposals = (data: ProposalListFieldsFragment[]) =>
|
|||||||
|
|
||||||
export const ProposalsList = () => {
|
export const ProposalsList = () => {
|
||||||
const gridRef = useRef<AgGridReact | null>(null);
|
const gridRef = useRef<AgGridReact | null>(null);
|
||||||
|
const [dataCount, setDataCount] = useState(0);
|
||||||
const handleOnGridReady = useCallback(() => {
|
const handleOnGridReady = useCallback(() => {
|
||||||
gridRef.current?.api?.sizeColumnsToFit();
|
gridRef.current?.api?.sizeColumnsToFit();
|
||||||
}, [gridRef]);
|
}, [gridRef]);
|
||||||
@ -30,22 +39,37 @@ export const ProposalsList = () => {
|
|||||||
});
|
});
|
||||||
const filteredData = getNewMarketProposals(data || []);
|
const filteredData = getNewMarketProposals(data || []);
|
||||||
const { columnDefs, defaultColDef } = useColumnDefs();
|
const { columnDefs, defaultColDef } = useColumnDefs();
|
||||||
|
useEffect(() => {
|
||||||
|
setDataCount(gridRef.current?.api?.getModel().getRowCount() ?? 0);
|
||||||
|
}, [filteredData]);
|
||||||
|
const onFilterChanged = useCallback(() => {
|
||||||
|
setDataCount(gridRef.current?.api?.getModel().getRowCount() ?? 0);
|
||||||
|
}, []);
|
||||||
return (
|
return (
|
||||||
<AsyncRenderer
|
<div className="relative">
|
||||||
loading={loading}
|
|
||||||
error={error}
|
|
||||||
data={filteredData}
|
|
||||||
reload={reload}
|
|
||||||
>
|
|
||||||
<AgGrid
|
<AgGrid
|
||||||
ref={gridRef}
|
ref={gridRef}
|
||||||
|
className="w-full h-full"
|
||||||
domLayout="autoHeight"
|
domLayout="autoHeight"
|
||||||
className="min-w-full"
|
|
||||||
columnDefs={columnDefs}
|
columnDefs={columnDefs}
|
||||||
rowData={filteredData}
|
rowData={filteredData}
|
||||||
defaultColDef={defaultColDef}
|
defaultColDef={defaultColDef}
|
||||||
onGridReady={handleOnGridReady}
|
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>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import BigNumber from 'bignumber.js';
|
import BigNumber from 'bignumber.js';
|
||||||
import type { ColDef } from 'ag-grid-community';
|
import type { ColDef } from 'ag-grid-community';
|
||||||
|
import { DateRangeFilter, SetFilter } from '@vegaprotocol/datagrid';
|
||||||
import { useEnvironment } from '@vegaprotocol/environment';
|
import { useEnvironment } from '@vegaprotocol/environment';
|
||||||
import { getDateTimeFormat } from '@vegaprotocol/utils';
|
import { getDateTimeFormat } from '@vegaprotocol/utils';
|
||||||
import { t } from '@vegaprotocol/i18n';
|
import { t } from '@vegaprotocol/i18n';
|
||||||
@ -73,6 +74,10 @@ export const useColumnDefs = () => {
|
|||||||
value,
|
value,
|
||||||
}: VegaValueFormatterParams<ProposalListFieldsFragment, 'state'>) =>
|
}: VegaValueFormatterParams<ProposalListFieldsFragment, 'state'>) =>
|
||||||
value ? ProposalStateMapping[value] : '-',
|
value ? ProposalStateMapping[value] : '-',
|
||||||
|
filter: SetFilter,
|
||||||
|
filterParams: {
|
||||||
|
set: ProposalStateMapping,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
colId: 'voting',
|
colId: 'voting',
|
||||||
@ -99,6 +104,7 @@ export const useColumnDefs = () => {
|
|||||||
}
|
}
|
||||||
return '-';
|
return '-';
|
||||||
},
|
},
|
||||||
|
filter: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
colId: 'closing-date',
|
colId: 'closing-date',
|
||||||
@ -110,6 +116,7 @@ export const useColumnDefs = () => {
|
|||||||
ProposalListFieldsFragment,
|
ProposalListFieldsFragment,
|
||||||
'terms.closingDatetime'
|
'terms.closingDatetime'
|
||||||
>) => (value ? getDateTimeFormat().format(new Date(value)) : '-'),
|
>) => (value ? getDateTimeFormat().format(new Date(value)) : '-'),
|
||||||
|
filter: DateRangeFilter,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
colId: 'enactment-date',
|
colId: 'enactment-date',
|
||||||
@ -121,13 +128,18 @@ export const useColumnDefs = () => {
|
|||||||
ProposalListFieldsFragment,
|
ProposalListFieldsFragment,
|
||||||
'terms.enactmentDatetime'
|
'terms.enactmentDatetime'
|
||||||
>) => (value ? getDateTimeFormat().format(new Date(value)) : '-'),
|
>) => (value ? getDateTimeFormat().format(new Date(value)) : '-'),
|
||||||
|
filter: DateRangeFilter,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
}, [VEGA_TOKEN_URL, requiredMajorityPercentage]);
|
}, [VEGA_TOKEN_URL, requiredMajorityPercentage]);
|
||||||
const defaultColDef: ColDef = useMemo(() => {
|
const defaultColDef: ColDef = useMemo(() => {
|
||||||
return {
|
return {
|
||||||
sortable: false,
|
sortable: true,
|
||||||
cellClass: cellCss,
|
cellClass: cellCss,
|
||||||
|
flex: 1,
|
||||||
|
resizable: true,
|
||||||
|
filter: true,
|
||||||
|
filterParams: { buttons: ['reset'] },
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
return useMemo(
|
return useMemo(
|
||||||
|
Loading…
Reference in New Issue
Block a user