feat(explorer): improve empty states and loading indicators (#2496)

* feat(explorer): initial empty list component on block txs list

* feat(explorer): messages formatting

* chore(explorer): update generated types

* feat(explorer): empty state for markets and assets and governance and blocks and txs

* feat(explorer): use loader rather than the word loading

* feat(explorer): use loader rather than the word loading in more places

* feat(explorer): empty state appears below headers in more pages

* feat(explorer): txs per block update

* feat(explorer): update tests to match new messages

* test(explorer): add test for loading and empty states for assets

* test(explorer): add test for loading and empty states for more routes

* test(explorer): change loading detector
This commit is contained in:
Edd 2023-01-05 13:10:42 +00:00 committed by GitHub
parent 35de756120
commit 53d3d5ac1c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 318 additions and 69 deletions

View File

@ -116,7 +116,7 @@ context('Blocks page', { tags: '@regression' }, function () {
});
function waitForBlocksResponse() {
cy.contains('Loading...').should('not.exist', { timeout: 18000 });
cy.get('[data-testid="loader"]').should('not.exist', { timeout: 18000 });
}
function validateBlocksDisplayed() {

View File

@ -70,7 +70,7 @@
"executor": "@nrwl/workspace:run-commands",
"options": {
"commands": [
"npx openapi-typescript https://raw.githubusercontent.com/vegaprotocol/documentation/main/specs/v0.62.1/blockexplorer.openapi.json --output apps/explorer/src/types/explorer.d.ts --immutable-types"
"npx openapi-typescript https://raw.githubusercontent.com/vegaprotocol/documentation/main/specs/v0.65.1/blockexplorer.openapi.json --output apps/explorer/src/types/explorer.d.ts --immutable-types"
]
}
},

View File

@ -59,7 +59,8 @@ describe('Blocks infinite list', () => {
error={undefined}
/>
);
expect(screen.getByText('No items')).toBeInTheDocument();
expect(screen.getByTestId('emptylist')).toBeInTheDocument();
expect(screen.getByText('This chain has 0 blocks')).toBeInTheDocument();
});
it('error is displayed at item level', () => {

View File

@ -4,6 +4,8 @@ import InfiniteLoader from 'react-window-infinite-loader';
import { t } from '@vegaprotocol/react-helpers';
import type { BlockMeta } from '../../routes/blocks/tendermint-blockchain-response';
import { BlockData } from './block-data';
import EmptyList from '../empty-list/empty-list';
import { Loader } from '@vegaprotocol/ui-toolkit';
interface BlocksInfiniteListProps {
hasMoreBlocks: boolean;
@ -31,7 +33,16 @@ export const BlocksInfiniteList = ({
className,
}: BlocksInfiniteListProps) => {
if (!blocks) {
return <div>No items</div>;
if (!areBlocksLoading) {
return (
<EmptyList
heading={t('This chain has 0 blocks')}
label={t('Check back soon')}
/>
);
} else {
return <Loader />;
}
}
// If there are more items to be loaded then add an extra row to hold a loading indicator.
@ -50,7 +61,7 @@ export const BlocksInfiniteList = ({
if (error) {
content = t(`${error}`);
} else if (!isItemLoaded(index)) {
content = t('Loading...');
content = <Loader />;
} else {
content = <BlockData block={blocks[index]} />;
}

View File

@ -0,0 +1,34 @@
export type EmptyListProps = {
heading?: string;
label?: string;
};
/**
* Renders the empty state from github ticket #1463
*/
const EmptyList = ({ heading, label }: EmptyListProps) => {
return (
<div
className="empty-list w-full items-center h-full align-center"
data-testid="emptylist"
>
<div className="skeleton-list border-dashed border-neutral-800 rounded p-5 w-full border-[1px] grid gap-4 grid-cols-9 grid-rows-1 place-content-around mb-4">
<div className="bg-neutral-900 mr-5 h-3 col-span-5"></div>
<div className="bg-neutral-900 h-3 col-span-1"></div>
</div>
<div className="mt-4">
{heading ? (
<h1 className="font-alpha text-xl uppercase text-center leading-relaxed">
{heading}
</h1>
) : null}
{label ? (
<p className="font-alpha text-gray-500 text-center">{label}</p>
) : null}
</div>
</div>
);
};
export default EmptyList;

View File

@ -14,8 +14,6 @@ export const methodText: Record<
METHOD_NOW: 'Immediate',
METHOD_UNSPECIFIED: 'Unspecified',
METHOD_AT_END_OF_EPOCH: 'End of epoch',
// This will be removed in a future release
METHOD_IN_ANGER: 'Immediate',
};
interface TxDetailsUndelegateProps {

View File

@ -46,7 +46,10 @@ describe('Txs infinite list', () => {
error={undefined}
/>
);
expect(screen.getByText('No items')).toBeInTheDocument();
expect(screen.getByTestId('emptylist')).toBeInTheDocument();
expect(
screen.getByText('This chain has 0 transactions')
).toBeInTheDocument();
});
it('error is displayed at item level', () => {

View File

@ -4,6 +4,8 @@ import InfiniteLoader from 'react-window-infinite-loader';
import { t, useScreenDimensions } from '@vegaprotocol/react-helpers';
import { TxsInfiniteListItem } from './txs-infinite-list-item';
import type { BlockExplorerTransactionResult } from '../../routes/types/block-explorer-response';
import EmptyList from '../empty-list/empty-list';
import { Loader } from '@vegaprotocol/ui-toolkit';
interface TxsInfiniteListProps {
hasMoreTxs: boolean;
@ -29,7 +31,7 @@ const Item = ({ index, style, isLoading, error }: ItemProps) => {
if (error) {
content = t(`Cannot fetch transaction: ${error}`);
} else if (isLoading) {
content = t('Loading...');
content = <Loader />;
} else {
const {
hash,
@ -68,7 +70,16 @@ export const TxsInfiniteList = ({
const isStacked = ['xs', 'sm', 'md', 'lg'].includes(screenSize);
if (!txs) {
return <div>No items</div>;
if (!areTxsLoading) {
return (
<EmptyList
heading={t('This chain has 0 transactions')}
label={t('Check back soon')}
/>
);
} else {
return <Loader />;
}
}
// If there are more items to be loaded then add an extra row to hold a loading indicator.

View File

@ -8,6 +8,8 @@ import type { BlockExplorerTransactions } from '../../routes/types/block-explore
import isNumber from 'lodash/isNumber';
import { ChainResponseCode } from './details/chain-response-code/chain-reponse.code';
import { getTxsDataUrl } from '../../hooks/use-txs-data';
import { Loader } from '@vegaprotocol/ui-toolkit';
import EmptyList from '../empty-list/empty-list';
interface TxsPerBlockProps {
blockHeight: string;
@ -84,10 +86,13 @@ export const TxsPerBlock = ({ blockHeight, txCount }: TxsPerBlockProps) => {
</tbody>
</Table>
</div>
) : loading ? (
<Loader />
) : (
<div className="sr-only">
{t(`No transactions in block ${blockHeight}`)}
</div>
<EmptyList
heading={t('No transactions in this block')}
label={t('0 transactions')}
/>
)}
</RenderFetched>
);

View File

@ -0,0 +1,44 @@
import { MockedProvider } from '@apollo/client/testing';
import { render } from '@testing-library/react';
import { MemoryRouter } from 'react-router-dom';
import Assets from './index';
import type { MockedResponse } from '@apollo/client/testing';
import { ExplorerAssetDocument } from '../../components/links/asset-link/__generated__/Asset';
function renderComponent(mock: MockedResponse[]) {
return (
<MemoryRouter>
<MockedProvider mocks={mock}>
<Assets />
</MockedProvider>
</MemoryRouter>
);
}
describe('Assets index', () => {
it('Renders loader when loading', async () => {
const mock = {
request: {
query: ExplorerAssetDocument,
},
result: {
data: {},
},
};
const res = render(renderComponent([mock]));
expect(await res.findByTestId('loader')).toBeInTheDocument();
});
it('Renders EmptyList when loading completes and there are no results', async () => {
const mock = {
request: {
query: ExplorerAssetDocument,
},
result: {
data: {},
},
};
const res = render(renderComponent([mock]));
expect(await res.findByTestId('emptylist')).toBeInTheDocument();
});
});

View File

@ -2,14 +2,15 @@ import { getNodes, t } from '@vegaprotocol/react-helpers';
import React from 'react';
import { RouteTitle } from '../../components/route-title';
import { SubHeading } from '../../components/sub-heading';
import { SyntaxHighlighter } from '@vegaprotocol/ui-toolkit';
import { Loader, SyntaxHighlighter } from '@vegaprotocol/ui-toolkit';
import { useExplorerAssetsQuery } from './__generated__/Assets';
import type { AssetsFieldsFragment } from './__generated__/Assets';
import { useScrollToLocation } from '../../hooks/scroll-to-location';
import { useDocumentTitle } from '../../hooks/use-document-title';
import EmptyList from '../../components/empty-list/empty-list';
const Assets = () => {
const { data } = useExplorerAssetsQuery();
const { data, loading } = useExplorerAssetsQuery();
useDocumentTitle(['Assets']);
useScrollToLocation();
@ -17,17 +18,25 @@ const Assets = () => {
const assets = getNodes<AssetsFieldsFragment>(data?.assetsConnection);
if (!assets || assets.length === 0) {
return <section></section>;
if (!loading) {
return (
<section>
<RouteTitle data-testid="assets-header">{t('Assets')}</RouteTitle>
<EmptyList
heading={t('This chain has no assets')}
label={t('0 assets')}
/>
</section>
);
} else {
return <Loader />;
}
}
return (
<section>
<RouteTitle data-testid="assets-header">{t('Assets')}</RouteTitle>
{assets.map((a) => {
if (!a) {
return null;
}
return (
<React.Fragment key={a.id}>
<SubHeading data-testid="asset-header" id={a.id}>

View File

@ -18,6 +18,7 @@ import { RenderFetched } from '../../../components/render-fetched';
import { t, useFetch } from '@vegaprotocol/react-helpers';
import { NodeLink } from '../../../components/links';
import { useDocumentTitle } from '../../../hooks/use-document-title';
import EmptyList from '../../../components/empty-list/empty-list';
const Block = () => {
const { block } = useParams<{ block: string }>();
@ -112,7 +113,12 @@ const Block = () => {
blockHeight={blockData.result.block.header.height}
txCount={blockData.result.block.data.txs.length}
/>
) : null}
) : (
<EmptyList
heading={t('This block is empty')}
label={t('0 transactions')}
/>
)}
</>
)}
</>

View File

@ -1,6 +1,6 @@
import { t, useFetch } from '@vegaprotocol/react-helpers';
import { RouteTitle } from '../../components/route-title';
import { SyntaxHighlighter } from '@vegaprotocol/ui-toolkit';
import { Loader, SyntaxHighlighter } from '@vegaprotocol/ui-toolkit';
import { DATA_SOURCES } from '../../config';
import type { TendermintGenesisResponse } from './tendermint-genesis-response';
import { useDocumentTitle } from '../../hooks/use-document-title';
@ -9,11 +9,16 @@ const Genesis = () => {
useDocumentTitle(['Genesis']);
const {
state: { data: genesis },
state: { data: genesis, loading },
} = useFetch<TendermintGenesisResponse>(
`${DATA_SOURCES.tendermintUrl}/genesis`
);
if (!genesis?.result.genesis) return null;
if (!genesis?.result.genesis) {
if (loading) {
return <Loader />;
}
return null;
}
return (
<section>
<RouteTitle data-testid="genesis-header">{t('Genesis')}</RouteTitle>

View File

@ -2,19 +2,35 @@ import { t } from '@vegaprotocol/react-helpers';
import React from 'react';
import { RouteTitle } from '../../components/route-title';
import { SubHeading } from '../../components/sub-heading';
import { SyntaxHighlighter } from '@vegaprotocol/ui-toolkit';
import { Loader, SyntaxHighlighter } from '@vegaprotocol/ui-toolkit';
import { useExplorerProposalsQuery } from './__generated__/Proposals';
import { useDocumentTitle } from '../../hooks/use-document-title';
import EmptyList from '../../components/empty-list/empty-list';
const Governance = () => {
const { data } = useExplorerProposalsQuery({
const { data, loading } = useExplorerProposalsQuery({
errorPolicy: 'ignore',
});
useDocumentTitle();
if (!data || !data.proposalsConnection || !data.proposalsConnection.edges) {
return <section></section>;
if (!loading) {
return (
<section>
<RouteTitle data-testid="governance-header">
{t('Governance Proposals')}
</RouteTitle>
<EmptyList
heading={t('This chain has no proposals')}
label={t('0 proposals')}
/>
</section>
);
} else {
return <Loader />;
}
}
const proposals = data?.proposalsConnection?.edges.map((e) => {

View File

@ -0,0 +1,48 @@
import { MockedProvider } from '@apollo/client/testing';
import { render } from '@testing-library/react';
import { MemoryRouter } from 'react-router-dom';
import Markets from './index';
import type { MockedResponse } from '@apollo/client/testing';
import { ExplorerMarketsDocument } from './__generated__/Markets';
function renderComponent(mock: MockedResponse[]) {
return (
<MemoryRouter>
<MockedProvider mocks={mock}>
<Markets />
</MockedProvider>
</MemoryRouter>
);
}
describe('Markets index', () => {
it('Renders loader when loading', async () => {
const mock = {
request: {
query: ExplorerMarketsDocument,
},
result: {
data: {
marketsConnection: [],
},
},
};
const res = render(renderComponent([mock]));
expect(await res.findByTestId('loader')).toBeInTheDocument();
});
it('Renders EmptyList when loading completes and there are no results', async () => {
const mock = {
request: {
query: ExplorerMarketsDocument,
},
result: {
data: {
marketsConnection: [],
},
},
};
const res = render(renderComponent([mock]));
expect(await res.findByTestId('emptylist')).toBeInTheDocument();
});
});

View File

@ -1,14 +1,15 @@
import React from 'react';
import { SyntaxHighlighter } from '@vegaprotocol/ui-toolkit';
import { Loader, SyntaxHighlighter } from '@vegaprotocol/ui-toolkit';
import { RouteTitle } from '../../components/route-title';
import { SubHeading } from '../../components/sub-heading';
import { t } from '@vegaprotocol/react-helpers';
import { useExplorerMarketsQuery } from './__generated__/Markets';
import { useScrollToLocation } from '../../hooks/scroll-to-location';
import { useDocumentTitle } from '../../hooks/use-document-title';
import EmptyList from '../../components/empty-list/empty-list';
const Markets = () => {
const { data } = useExplorerMarketsQuery();
const { data, loading } = useExplorerMarketsQuery();
useScrollToLocation();
useDocumentTitle(['Markets']);
@ -19,16 +20,23 @@ const Markets = () => {
<section key="markets">
<RouteTitle data-testid="markets-heading">{t('Markets')}</RouteTitle>
{m
? m.map((e) => (
<React.Fragment key={e.node.id}>
<SubHeading data-testid="markets-header" id={e.node.id}>
{e.node.tradableInstrument.instrument.name}
</SubHeading>
<SyntaxHighlighter data={e.node} />
</React.Fragment>
))
: null}
{m ? (
m.map((e) => (
<React.Fragment key={e.node.id}>
<SubHeading data-testid="markets-header" id={e.node.id}>
{e.node.tradableInstrument.instrument.name}
</SubHeading>
<SyntaxHighlighter data={e.node} />
</React.Fragment>
))
) : loading ? (
<Loader />
) : (
<EmptyList
heading={t('This chain has no markets')}
label={t('0 markets')}
/>
)}
</section>
);
};

View File

@ -1,8 +1,7 @@
import { t } from '@vegaprotocol/react-helpers';
import React from 'react';
import { RouteTitle } from '../../components/route-title';
import { SubHeading } from '../../components/sub-heading';
import { SyntaxHighlighter } from '@vegaprotocol/ui-toolkit';
import { Loader, SyntaxHighlighter } from '@vegaprotocol/ui-toolkit';
import { DATA_SOURCES } from '../../config';
import { useFetch } from '@vegaprotocol/react-helpers';
import type { TendermintValidatorsResponse } from './tendermint-validator-response';
@ -28,7 +27,9 @@ const Validators = () => {
<SubHeading data-testid="vega-header">{t('Vega data')}</SubHeading>
<SyntaxHighlighter data-testid="vega-data" data={data} />
</>
) : null}
) : (
<Loader />
)}
{validators ? (
<>
<SubHeading data-testid="tendermint-header">
@ -36,7 +37,9 @@ const Validators = () => {
</SubHeading>
<SyntaxHighlighter data-testid="tendermint-data" data={validators} />
</>
) : null}
) : (
<Loader />
)}
</section>
);
};

View File

@ -14,9 +14,17 @@ type OneOf<T extends any[]> = T extends [infer Only]
: T extends [infer A, infer B, ...infer Rest]
? OneOf<[XOR<A, B>, ...Rest]>
: never;
/* typescript-eslint:enable no-explicit-any */
/* eslint-enable @typescript-eslint/no-explicit-any */
export interface paths {
'/info': {
/**
* Info
* @description Retrieves information about the block explorer.
* Response contains a semver formatted version of the data node and the commit hash, from which the block explorer was built,
*/
get: operations['BlockExplorer_Info'];
};
'/transactions': {
/**
* List transactions
@ -100,8 +108,7 @@ export interface components {
readonly UndelegateSubmissionMethod:
| 'METHOD_UNSPECIFIED'
| 'METHOD_NOW'
| 'METHOD_AT_END_OF_EPOCH'
| 'METHOD_IN_ANGER';
| 'METHOD_AT_END_OF_EPOCH';
readonly blockexplorerapiv1Transaction: {
/**
* The height of the block the transaction was found in
@ -117,6 +124,11 @@ export interface components {
readonly command?: components['schemas']['v1InputData'];
/** The cursor for this transaction (in the page, used for paginated results) */
readonly cursor?: string;
/**
* An optional error happening when processing / checking the transaction
* Should be set if error code is not 0
*/
readonly error?: string;
/** The hash of the transaction */
readonly hash?: string;
/**
@ -124,6 +136,8 @@ export interface components {
* Format: int64
*/
readonly index?: number;
/** Submitter's signature of transaction */
readonly signature?: components['schemas']['v1Signature'];
/** The submitter of the transaction (Vega public key) */
readonly submitter?: string;
/** The type of transaction */
@ -159,7 +173,7 @@ export interface components {
readonly '@type'?: string;
[key: string]: unknown | undefined;
};
/** Used announce a node as a new potential validator */
/** Used announce a node as a new pending validator */
readonly v1AnnounceNode: {
/** AvatarURL of the validator */
readonly avatarUrl?: string;
@ -192,7 +206,7 @@ export interface components {
* Format: int64
*/
readonly vegaPubKeyIndex?: number;
/** Signature from the validator made using the vega wallet */
/** Signature from the validator made using the Vega wallet */
readonly vegaSignature?: components['schemas']['v1Signature'];
};
/**
@ -287,6 +301,12 @@ export interface components {
/** The transaction corresponding to the hash */
readonly transaction?: components['schemas']['blockexplorerapiv1Transaction'];
};
readonly v1InfoResponse: {
/** The commit hash from which the data-node was built */
readonly commitHash?: string;
/** A semver formatted version of the data node */
readonly version?: string;
};
readonly v1InputData: {
readonly announceNode?: components['schemas']['v1AnnounceNode'];
readonly batchMarketInstructions?: components['schemas']['v1BatchMarketInstructions'];
@ -351,7 +371,7 @@ export interface components {
/** The ID of the node that will be signed in or out of the smartcontract */
readonly validatorNodeId?: string;
};
/** A transaction to allow validator to rotate their vega keys */
/** A transaction to allow validator to rotate their Vega keys */
readonly v1KeyRotateSubmission: {
/** Hash of currently used public key */
readonly currentPubKeyHash?: string;
@ -414,7 +434,7 @@ export interface components {
readonly sig?: string;
};
/**
* The kind of the signature created by a node, for example, allow-listing a new asset, withdrawal etc
* The kind of signature created by a node, for example, allow-listing a new asset, withdrawal etc
* @description - NODE_SIGNATURE_KIND_UNSPECIFIED: Represents an unspecified or missing value from the input
* - NODE_SIGNATURE_KIND_ASSET_NEW: Represents a signature for a new asset allow-listing
* - NODE_SIGNATURE_KIND_ASSET_WITHDRAWAL: Represents a signature for an asset withdrawal
@ -432,7 +452,7 @@ export interface components {
| 'NODE_SIGNATURE_KIND_ERC20_MULTISIG_SIGNER_REMOVED'
| 'NODE_SIGNATURE_KIND_ASSET_UPDATE';
/**
* Used when a node votes for validating a given resource exists or is valid,
* Used when a node votes for validating that a given resource exists or is valid,
* for example, an ERC20 deposit is valid and exists on ethereum
*/
readonly v1NodeVote: {
@ -553,6 +573,12 @@ export interface components {
readonly v1PropertyKey: {
/** @description name is the name of the property. */
readonly name?: string;
/**
* An optional decimal place to be be applied on the provided value
* valid only for PropertyType of type DECIMAL and INTEGER
* Format: uint64
*/
readonly numberDecimalPlaces?: string;
/** @description type is the type of the property. */
readonly type?: components['schemas']['v1PropertyKeyType'];
};
@ -596,7 +622,7 @@ export interface components {
* Format: uint64
*/
readonly upgradeBlockHeight?: string;
/** the release tag for the vega binary */
/** the release tag for the Vega binary */
readonly vegaReleaseTag?: string;
};
/**
@ -659,8 +685,8 @@ export interface components {
readonly nodeId?: string;
};
/**
* A message from a validator signaling they are still online and validating blocks
* or ready to validate block when they are till a potential validator
* A message from a validator signalling they are still online and validating blocks
* or ready to validate blocks when they are still a pending validator
*/
readonly v1ValidatorHeartbeat: {
/** Signature from the validator made using the ethereum wallet */
@ -1061,11 +1087,6 @@ export interface components {
readonly quoteName?: string;
/** Asset ID for the product's settlement asset */
readonly settlementAsset?: string;
/**
* The number of decimal places implied by the settlement data (such as price) emitted by the settlement data source
* Format: int64
*/
readonly settlementDataDecimals?: number;
};
/** Instrument configuration */
readonly vegaInstrumentConfiguration: {
@ -1111,17 +1132,17 @@ export interface components {
/** Risk model parameters for log normal */
readonly vegaLogNormalModelParams: {
/**
* Mu param
* Mu parameter, annualised growth rate of the underlying asset
* Format: double
*/
readonly mu?: number;
/**
* R param
* R parameter, annualised growth rate of the risk-free asset, used for discounting of future cash flows, can be any real number
* Format: double
*/
readonly r?: number;
/**
* Sigma param
* Sigma parameter, annualised volatility of the underlying asset, must be a strictly non-negative real number
* Format: double
*/
readonly sigma?: number;
@ -1136,7 +1157,7 @@ export interface components {
*/
readonly riskAversionParameter?: number;
/**
* Tau
* Tau parameter of the risk model, projection horizon measured as a year fraction used in the expected shortfall calculation to obtain the maintenance margin, must be a strictly non-negative real number
* Format: double
*/
readonly tau?: number;
@ -1180,6 +1201,11 @@ export interface components {
readonly liquidityMonitoringParameters?: components['schemas']['vegaLiquidityMonitoringParameters'];
/** Log normal risk model parameters, valid only if MODEL_LOG_NORMAL is selected */
readonly logNormal?: components['schemas']['vegaLogNormalRiskModel'];
/**
* Percentage move up and down from the mid price which specifies the range of
* price levels over which automated liquidity provision orders will be deployed
*/
readonly lpPriceRange?: string;
/** Optional new market meta data, tags */
readonly metadata?: readonly string[];
/**
@ -1239,7 +1265,7 @@ export interface components {
readonly vegaPriceMonitoringTrigger: {
/**
* Price monitoring auction extension duration in seconds should the price
* breach it's theoretical level over the specified horizon at the specified
* breach its theoretical level over the specified horizon at the specified
* probability level
* Format: int64
*/
@ -1436,11 +1462,6 @@ export interface components {
readonly dataSourceSpecForTradingTermination?: components['schemas']['vegaDataSourceDefinition'];
/** Human-readable name/abbreviation of the quote name */
readonly quoteName?: string;
/**
* The number of decimal places implied by the settlement data (such as price) emitted by the settlement external data source
* Format: int64
*/
readonly settlementDataDecimals?: number;
};
/** Instrument configuration */
readonly vegaUpdateInstrumentConfiguration: {
@ -1464,6 +1485,11 @@ export interface components {
readonly liquidityMonitoringParameters?: components['schemas']['vegaLiquidityMonitoringParameters'];
/** Log normal risk model parameters, valid only if MODEL_LOG_NORMAL is selected */
readonly logNormal?: components['schemas']['vegaLogNormalRiskModel'];
/**
* Percentage move up and down from the mid price which specifies the range of
* price levels over which automated liquidity provision orders will be deployed
*/
readonly lpPriceRange?: string;
/** Optional market metadata, tags */
readonly metadata?: readonly string[];
/** Price monitoring parameters */
@ -1504,6 +1530,27 @@ export interface components {
export type external = Record<string, never>;
export interface operations {
BlockExplorer_Info: {
/**
* Info
* @description Retrieves information about the block explorer.
* Response contains a semver formatted version of the data node and the commit hash, from which the block explorer was built,
*/
responses: {
/** @description A successful response. */
200: {
content: {
readonly 'application/json': components['schemas']['v1InfoResponse'];
};
};
/** @description An unexpected error response. */
default: {
content: {
readonly 'application/json': components['schemas']['googlerpcStatus'];
};
};
};
};
BlockExplorer_ListTransactions: {
/**
* List transactions