fix(trading): fix proposals not showing (#3859)

This commit is contained in:
Matthew Russell 2023-05-20 02:55:52 -07:00 committed by GitHub
parent 65747e8d26
commit b499c293e3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 105 additions and 64 deletions

View File

@ -12,7 +12,7 @@ export const Proposed = () => {
const externalLink = tokenLink(TOKEN_NEW_MARKET_PROPOSAL);
return (
<>
<div className="min-h-[200px]">
<div className="h-[400px]">
<ProposalsList />
</div>
<ExternalLink className="py-4 px-[11px] text-sm" href={externalLink}>

View File

@ -5,57 +5,74 @@ import {
waitFor,
getAllByRole,
} from '@testing-library/react';
import merge from 'lodash/merge';
import type { MockedResponse } from '@apollo/client/testing';
import { MockedProvider } from '@apollo/client/testing';
import { ProposalsList } from './proposals-list';
import type { ProposalListFieldsFragment } from '../../lib/proposals-data-provider';
import * as Types from '@vegaprotocol/types';
const votesMock = {
yes: {
totalTokens: '5000',
},
no: {
totalTokens: '2000',
},
};
let marketsProposalMock: ProposalListFieldsFragment[] | null = [
{
id: 'id-1',
state: Types.ProposalState.STATE_OPEN,
votes: { ...votesMock },
},
{
id: 'id-2',
state: Types.ProposalState.STATE_PASSED,
votes: { ...votesMock },
},
{
id: 'id-3',
state: Types.ProposalState.STATE_WAITING_FOR_NODE_VOTE,
votes: { ...votesMock },
},
] as ProposalListFieldsFragment[];
const useDataProvider = () => {
return {
data: marketsProposalMock,
loading: false,
error: false,
};
};
jest.mock('@vegaprotocol/data-provider', () => ({
...jest.requireActual('@vegaprotocol/data-provider'),
useDataProvider: jest.fn(() => useDataProvider()),
}));
import { createProposalListFieldsFragment } from '../../lib/proposals-data-provider/proposals.mock';
import type { ProposalsListQuery } from '../../lib';
import { ProposalsListDocument } from '../../lib';
import type { PartialDeep } from 'type-fest';
describe('ProposalsList', () => {
beforeEach(() => {
jest.clearAllMocks();
});
const createProposalsMock = (override?: PartialDeep<ProposalsListQuery>) => {
const defaultProposalEdges = [
{
__typename: 'ProposalEdge' as const,
node: createProposalListFieldsFragment({
id: 'id-1',
state: Types.ProposalState.STATE_OPEN,
}),
},
{
__typename: 'ProposalEdge' as const,
node: createProposalListFieldsFragment({
id: 'id-2',
state: Types.ProposalState.STATE_PASSED,
}),
},
{
__typename: 'ProposalEdge' as const,
node: createProposalListFieldsFragment({
id: 'id-3',
state: Types.ProposalState.STATE_WAITING_FOR_NODE_VOTE,
}),
},
];
const data = merge(
{
proposalsConnection: {
__typename: 'ProposalsConnection' as const,
edges: defaultProposalEdges,
},
},
override
);
const mock: MockedResponse<ProposalsListQuery> = {
request: {
query: ProposalsListDocument,
variables: {
proposalType: Types.ProposalType.TYPE_NEW_MARKET,
},
},
result: {
data,
},
};
return mock;
};
it('should be properly rendered', async () => {
const mock = createProposalsMock();
await act(() => {
render(<ProposalsList />, { wrapper: MockedProvider });
render(
<MockedProvider mocks={[mock]}>
<ProposalsList />
</MockedProvider>
);
});
const container = document.querySelector('.ag-center-cols-container');
await waitFor(() => {
@ -65,15 +82,25 @@ describe('ProposalsList', () => {
});
it('some of states should be filtered out', async () => {
marketsProposalMock = [
{
...(marketsProposalMock as ProposalListFieldsFragment[])[0],
state: Types.ProposalState.STATE_ENACTED,
const mock = createProposalsMock({
proposalsConnection: {
edges: [
{
__typename: 'ProposalEdge',
node: createProposalListFieldsFragment({
id: 'id-1',
state: Types.ProposalState.STATE_ENACTED,
}),
},
],
},
...(marketsProposalMock as ProposalListFieldsFragment[]).slice(1),
];
});
await act(() => {
render(<ProposalsList />, { wrapper: MockedProvider });
render(
<MockedProvider mocks={[mock]}>
<ProposalsList />
</MockedProvider>
);
});
const container = document.querySelector('.ag-center-cols-container');
await waitFor(() => {
@ -83,9 +110,12 @@ describe('ProposalsList', () => {
});
it('empty response should causes no data message display', async () => {
marketsProposalMock = null;
await act(() => {
render(<ProposalsList />, { wrapper: MockedProvider });
render(
<MockedProvider>
<ProposalsList />
</MockedProvider>
);
});
const container = document.querySelector('.ag-center-cols-container');
await waitFor(() => {

View File

@ -1,13 +1,13 @@
import { useCallback, useEffect, useRef, useState } from 'react';
import { AsyncRenderer } from '@vegaprotocol/ui-toolkit';
import { AgGridLazy as AgGrid } from '@vegaprotocol/datagrid';
import { useDataProvider } from '@vegaprotocol/data-provider';
import { t } from '@vegaprotocol/i18n';
import * as Types from '@vegaprotocol/types';
import { proposalsDataProvider } from '../../lib/proposals-data-provider';
import type { AgGridReact } from 'ag-grid-react';
import { useColumnDefs } from './use-column-defs';
import type { ProposalListFieldsFragment } from '../../lib/proposals-data-provider/__generated__/Proposals';
import { useProposalsListQuery } from '../../lib/proposals-data-provider/__generated__/Proposals';
import { removePaginationWrapper } from '@vegaprotocol/utils';
export const getNewMarketProposals = (data: ProposalListFieldsFragment[]) =>
data.filter((proposal) =>
@ -21,13 +21,15 @@ export const getNewMarketProposals = (data: ProposalListFieldsFragment[]) =>
export const ProposalsList = () => {
const gridRef = useRef<AgGridReact | null>(null);
const [dataCount, setDataCount] = useState(0);
const { data, loading, error, reload } = useDataProvider({
dataProvider: proposalsDataProvider,
const { data, loading, error, refetch } = useProposalsListQuery({
variables: {
proposalType: Types.ProposalType.TYPE_NEW_MARKET,
},
errorPolicy: 'all', // currently there are some proposals failing due to proposals existing without settlement asset ids
});
const filteredData = getNewMarketProposals(data || []);
const filteredData = getNewMarketProposals(
removePaginationWrapper(data?.proposalsConnection?.edges)
);
const { columnDefs, defaultColDef } = useColumnDefs();
useEffect(() => {
setDataCount(gridRef.current?.api?.getModel().getRowCount() ?? 0);
@ -36,11 +38,10 @@ export const ProposalsList = () => {
setDataCount(gridRef.current?.api?.getModel().getRowCount() ?? 0);
}, []);
return (
<div className="relative">
<div className="relative h-full">
<AgGrid
ref={gridRef}
className="w-full h-full"
domLayout="autoHeight"
columnDefs={columnDefs}
rowData={filteredData}
defaultColDef={defaultColDef}
@ -48,6 +49,8 @@ export const ProposalsList = () => {
suppressNoRowsOverlay
onFilterChanged={onFilterChanged}
storeKey="proposedMarkets"
getRowId={({ data }) => data.id}
style={{ width: '100%', height: '100%' }}
/>
<div className="pointer-events-none absolute inset-0">
<AsyncRenderer
@ -56,7 +59,7 @@ export const ProposalsList = () => {
data={filteredData}
noDataMessage={t('No markets')}
noDataCondition={() => !dataCount}
reload={reload}
reload={refetch}
/>
</div>
</div>

View File

@ -11,6 +11,7 @@ export const proposalListQuery = (
): ProposalsListQuery => {
const defaultResult: ProposalsListQuery = {
proposalsConnection: {
__typename: 'ProposalsConnection',
edges: proposalListFields.map((node) => ({
__typename: 'ProposalEdge',
node,
@ -104,8 +105,10 @@ export const marketUpdateProposal: ProposalListFieldsFragment = {
},
};
const proposalListFields: ProposalListFieldsFragment[] = [
{
export const createProposalListFieldsFragment = (
override?: PartialDeep<ProposalListFieldsFragment>
): ProposalListFieldsFragment => {
const defaultProposal: ProposalListFieldsFragment = {
id: 'e9ec6d5c46a7e7bcabf9ba7a893fa5a5eeeec08b731f06f7a6eb7bf0e605b829',
reference: 'injected_at_runtime',
state: Schema.ProposalState.STATE_OPEN,
@ -194,7 +197,12 @@ const proposalListFields: ProposalListFieldsFragment[] = [
__typename: 'ProposalTerms',
},
__typename: 'Proposal',
},
};
return merge(defaultProposal, override);
};
const proposalListFields: ProposalListFieldsFragment[] = [
createProposalListFieldsFragment(),
{
id: '1cd1deb532b97fbeb9262fe94499ecec5835e60ae564b7c5af530c90a13c29cb',
reference: 'injected_at_runtime',