Feat/300 network parameters table (#333)
* network parameters table with key value rows and syntax blobs only for json values * inline row not for syntax * add unit test for network param table * add cypress test to verify if values are non-empty * remove some comments * rename formatNumber method to addDecimalsFormatNumber and simplify formatNumber * remove duplicate expect line * use AsyncRenderer and sort params asc * refactor and add extra tests to check ordering and loading cases * format big number params with addDecimals formatNumber * Update apps/explorer/src/app/routes/network-parameters/network-parameters.tsx Co-authored-by: Dexter Edwards <dexter.edwards93@gmail.com> * capitalize and refactor tests * missing ; caused formatting to fail Co-authored-by: madalinaraicu <“madalina@raygroup.uk”> Co-authored-by: Dexter Edwards <dexter.edwards93@gmail.com>
This commit is contained in:
parent
431ea1bc80
commit
d03e4cf785
3
.vscode/extensions.json
vendored
3
.vscode/extensions.json
vendored
@ -3,6 +3,7 @@
|
||||
"nrwl.angular-console",
|
||||
"esbenp.prettier-vscode",
|
||||
"firsttris.vscode-jest-runner",
|
||||
"dbaeumer.vscode-eslint"
|
||||
"dbaeumer.vscode-eslint",
|
||||
"stevejpurves.cucumber"
|
||||
]
|
||||
}
|
||||
|
@ -9,3 +9,15 @@ Feature: Network parameters Page
|
||||
Given I am on mobile and open the toggle menu
|
||||
When I navigate to network parameters page
|
||||
Then network parameters page is correctly displayed
|
||||
|
||||
Scenario: Navigate to network parameters page and check each value is non-empty
|
||||
Given I am on the homepage
|
||||
When I navigate to network parameters page
|
||||
Then network parameters page is correctly displayed
|
||||
And each value is non-empty
|
||||
|
||||
Scenario: Navigate to network parameters page and check each value using mobile
|
||||
Given I am on mobile and open the toggle menu
|
||||
When I navigate to network parameters page
|
||||
Then network parameters page is correctly displayed
|
||||
And each value is non-empty
|
||||
|
@ -11,4 +11,12 @@ export default class NetworkParametersPage extends BasePage {
|
||||
);
|
||||
cy.getByTestId(this.parameters).should('not.be.empty');
|
||||
}
|
||||
|
||||
eachValueIsNonEmpty() {
|
||||
cy.getByTestId(this.parameters).then(($parameters) => {
|
||||
$parameters.each((_index, element) => {
|
||||
cy.wrap(element).should('not.be.empty');
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -9,3 +9,7 @@ When('I navigate to network parameters page', () => {
|
||||
Then('network parameters page is correctly displayed', () => {
|
||||
networkPage.verifyNetworkParametersDisplayed();
|
||||
});
|
||||
|
||||
Then('each value is non-empty', () => {
|
||||
networkPage.eachValueIsNonEmpty();
|
||||
});
|
||||
|
@ -1,28 +1 @@
|
||||
import { gql, useQuery } from '@apollo/client';
|
||||
import { RouteTitle } from '../../components/route-title';
|
||||
import type { NetworkParametersQuery } from './__generated__/NetworkParametersQuery';
|
||||
import { SyntaxHighlighter } from '@vegaprotocol/ui-toolkit';
|
||||
import { t } from '@vegaprotocol/react-helpers';
|
||||
|
||||
export const NETWORK_PARAMETERS_QUERY = gql`
|
||||
query NetworkParametersQuery {
|
||||
networkParameters {
|
||||
key
|
||||
value
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const NetworkParameters = () => {
|
||||
const { data } = useQuery<NetworkParametersQuery>(NETWORK_PARAMETERS_QUERY);
|
||||
return (
|
||||
<section>
|
||||
<RouteTitle data-testid="network-param-header">
|
||||
{t('Network Parameters')}
|
||||
</RouteTitle>
|
||||
{data ? <SyntaxHighlighter data={data} /> : null}
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default NetworkParameters;
|
||||
export * from './network-parameters';
|
||||
|
@ -0,0 +1,73 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { NetworkParametersTable } from './network-parameters';
|
||||
import type { NetworkParametersQuery } from './__generated__/NetworkParametersQuery';
|
||||
|
||||
describe('NetworkParametersTable', () => {
|
||||
it('renders correctly when it has network params', () => {
|
||||
const data: NetworkParametersQuery = {
|
||||
networkParameters: [
|
||||
{
|
||||
__typename: 'NetworkParameter',
|
||||
key: 'market.liquidityProvision.minLpStakeQuantumMultiple',
|
||||
value: '1',
|
||||
},
|
||||
{
|
||||
__typename: 'NetworkParameter',
|
||||
key: 'market.fee.factors.infrastructureFee',
|
||||
value: '0.0005',
|
||||
},
|
||||
],
|
||||
};
|
||||
render(<NetworkParametersTable data={data} loading={false} />);
|
||||
expect(screen.getByTestId('network-param-header')).toHaveTextContent(
|
||||
'Network Parameters'
|
||||
);
|
||||
const rows = screen.getAllByTestId('key-value-table-row');
|
||||
expect(rows[0].children[0]).toHaveTextContent(
|
||||
'market.fee.factors.infrastructureFee'
|
||||
);
|
||||
expect(rows[1].children[0]).toHaveTextContent(
|
||||
'market.liquidityProvision.minLpStakeQuantumMultiple'
|
||||
);
|
||||
expect(rows[0].children[1]).toHaveTextContent('0.0005');
|
||||
expect(rows[1].children[1]).toHaveTextContent('1');
|
||||
});
|
||||
|
||||
it('renders the rows in ascending order', () => {
|
||||
const data: NetworkParametersQuery = {
|
||||
networkParameters: [
|
||||
{
|
||||
__typename: 'NetworkParameter',
|
||||
key: 'market.fee.factors.infrastructureFee',
|
||||
value: '0.0005',
|
||||
},
|
||||
{
|
||||
__typename: 'NetworkParameter',
|
||||
key: 'market.liquidityProvision.minLpStakeQuantumMultiple',
|
||||
value: '1',
|
||||
},
|
||||
],
|
||||
};
|
||||
render(<NetworkParametersTable data={data} loading={false} />);
|
||||
expect(screen.getByTestId('network-param-header')).toHaveTextContent(
|
||||
'Network Parameters'
|
||||
);
|
||||
const rows = screen.getAllByTestId('key-value-table-row');
|
||||
expect(rows[0].children[0]).toHaveTextContent(
|
||||
'market.fee.factors.infrastructureFee'
|
||||
);
|
||||
expect(rows[1].children[0]).toHaveTextContent(
|
||||
'market.liquidityProvision.minLpStakeQuantumMultiple'
|
||||
);
|
||||
expect(rows[0].children[1]).toHaveTextContent('0.0005');
|
||||
expect(rows[1].children[1]).toHaveTextContent('1');
|
||||
});
|
||||
|
||||
it('does not render rows when is loading', () => {
|
||||
render(<NetworkParametersTable data={undefined} loading={true} />);
|
||||
expect(screen.getByTestId('network-param-header')).toHaveTextContent(
|
||||
'Network Parameters'
|
||||
);
|
||||
expect(screen.queryByTestId('key-value-table-row')).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
@ -0,0 +1,118 @@
|
||||
import { gql, useQuery } from '@apollo/client';
|
||||
import {
|
||||
AsyncRenderer,
|
||||
KeyValueTable,
|
||||
KeyValueTableRow,
|
||||
SyntaxHighlighter,
|
||||
} from '@vegaprotocol/ui-toolkit';
|
||||
import {
|
||||
addDecimalsFormatNumber,
|
||||
formatNumber,
|
||||
t,
|
||||
} from '@vegaprotocol/react-helpers';
|
||||
import { RouteTitle } from '../../components/route-title';
|
||||
import type {
|
||||
NetworkParametersQuery,
|
||||
NetworkParametersQuery_networkParameters,
|
||||
} from './__generated__/NetworkParametersQuery';
|
||||
import orderBy from 'lodash/orderBy';
|
||||
|
||||
const BIG_NUMBER_PARAMS = [
|
||||
'spam.protection.delegation.min.tokens',
|
||||
'validators.delegation.minAmount',
|
||||
'reward.staking.delegation.minimumValidatorStake',
|
||||
'reward.staking.delegation.maxPayoutPerParticipant',
|
||||
'reward.staking.delegation.maxPayoutPerEpoch',
|
||||
'spam.protection.voting.min.tokens',
|
||||
'governance.proposal.freeform.minProposerBalance',
|
||||
'governance.proposal.updateNetParam.minVoterBalance',
|
||||
'governance.proposal.updateMarket.minVoterBalance',
|
||||
'governance.proposal.asset.minVoterBalance',
|
||||
'governance.proposal.updateNetParam.minProposerBalance',
|
||||
'governance.proposal.freeform.minVoterBalance',
|
||||
'spam.protection.proposal.min.tokens',
|
||||
'governance.proposal.updateMarket.minProposerBalance',
|
||||
'governance.proposal.asset.minProposerBalance',
|
||||
];
|
||||
|
||||
export const renderRow = ({
|
||||
key,
|
||||
value,
|
||||
}: NetworkParametersQuery_networkParameters) => {
|
||||
const isSyntaxRow = isJsonObject(value);
|
||||
return (
|
||||
<KeyValueTableRow key={key} inline={!isSyntaxRow}>
|
||||
{key}
|
||||
{isSyntaxRow ? (
|
||||
<SyntaxHighlighter data={JSON.parse(value)} />
|
||||
) : isNaN(Number(value)) ? (
|
||||
value
|
||||
) : BIG_NUMBER_PARAMS.includes(key) ? (
|
||||
addDecimalsFormatNumber(Number(value), 4)
|
||||
) : (
|
||||
formatNumber(Number(value), 4)
|
||||
)}
|
||||
</KeyValueTableRow>
|
||||
);
|
||||
};
|
||||
|
||||
export const isJsonObject = (str: string) => {
|
||||
try {
|
||||
return JSON.parse(str) && Object.keys(JSON.parse(str)).length > 0;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
export const NETWORK_PARAMETERS_QUERY = gql`
|
||||
query NetworkParametersQuery {
|
||||
networkParameters {
|
||||
key
|
||||
value
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export interface NetworkParametersTableProps
|
||||
extends React.HTMLAttributes<HTMLTableElement> {
|
||||
data?: NetworkParametersQuery;
|
||||
error?: Error;
|
||||
loading: boolean;
|
||||
}
|
||||
|
||||
export const NetworkParametersTable = ({
|
||||
data,
|
||||
error,
|
||||
loading,
|
||||
}: NetworkParametersTableProps) => (
|
||||
<section>
|
||||
<RouteTitle data-testid="network-param-header">
|
||||
{t('Network Parameters')}
|
||||
</RouteTitle>
|
||||
|
||||
<AsyncRenderer
|
||||
data={data}
|
||||
loading={loading}
|
||||
error={error}
|
||||
render={(data) => {
|
||||
const ascParams = orderBy(
|
||||
data.networkParameters || [],
|
||||
(param) => param.key,
|
||||
'asc'
|
||||
);
|
||||
return (
|
||||
<KeyValueTable data-testid="parameters">
|
||||
{(ascParams || []).map((row) => renderRow(row))}
|
||||
</KeyValueTable>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</section>
|
||||
);
|
||||
|
||||
export const NetworkParameters = () => {
|
||||
const { data, loading, error } = useQuery<NetworkParametersQuery>(
|
||||
NETWORK_PARAMETERS_QUERY
|
||||
);
|
||||
return <NetworkParametersTable data={data} error={error} loading={loading} />;
|
||||
};
|
@ -9,7 +9,6 @@ import { Party as PartySingle } from './parties/id';
|
||||
import Txs from './txs';
|
||||
import Validators from './validators';
|
||||
import Genesis from './genesis';
|
||||
import NetworkParameters from './network-parameters';
|
||||
import { Block } from './blocks/id';
|
||||
import { Blocks } from './blocks/home';
|
||||
import { Tx } from './txs/id';
|
||||
@ -18,6 +17,7 @@ import { PendingTxs } from './pending';
|
||||
import flags from '../lib/flags';
|
||||
import { t } from '@vegaprotocol/react-helpers';
|
||||
import { Routes } from './route-names';
|
||||
import { NetworkParameters } from './network-parameters';
|
||||
|
||||
const partiesRoutes = flags.parties
|
||||
? [
|
||||
|
@ -2,7 +2,7 @@ import { forwardRef } from 'react';
|
||||
import type { ColumnApi, ValueFormatterParams } from 'ag-grid-community';
|
||||
import {
|
||||
PriceCell,
|
||||
formatNumber,
|
||||
addDecimalsFormatNumber,
|
||||
t,
|
||||
addSummaryRows,
|
||||
} from '@vegaprotocol/react-helpers';
|
||||
@ -136,7 +136,7 @@ export const AccountsTable = forwardRef<AgGridReact, AccountsTableProps>(
|
||||
value,
|
||||
data,
|
||||
}: AccountsTableValueFormatterParams) =>
|
||||
formatNumber(value, data.asset.decimals)
|
||||
addDecimalsFormatNumber(value, data.asset.decimals)
|
||||
}
|
||||
/>
|
||||
</AgGrid>
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { Icon, Loader } from '@vegaprotocol/ui-toolkit';
|
||||
import type { ReactNode } from 'react';
|
||||
import type { OrderEvent_busEvents_event_Order } from './__generated__/OrderEvent';
|
||||
import { formatNumber, t } from '@vegaprotocol/react-helpers';
|
||||
import { addDecimalsFormatNumber, t } from '@vegaprotocol/react-helpers';
|
||||
import type { VegaTxState } from '@vegaprotocol/wallet';
|
||||
import { VegaTxStatus } from '@vegaprotocol/wallet';
|
||||
|
||||
@ -76,7 +76,7 @@ export const OrderDialog = ({
|
||||
{finalizedOrder.type === 'Limit' && finalizedOrder.market && (
|
||||
<p>
|
||||
{t(
|
||||
`Price: ${formatNumber(
|
||||
`Price: ${addDecimalsFormatNumber(
|
||||
finalizedOrder.price,
|
||||
finalizedOrder.market.decimalPlaces
|
||||
)}`
|
||||
|
@ -3,7 +3,7 @@ import {
|
||||
PriceCell,
|
||||
Vol,
|
||||
CumulativeVol,
|
||||
formatNumber,
|
||||
addDecimalsFormatNumber,
|
||||
} from '@vegaprotocol/react-helpers';
|
||||
|
||||
interface OrderbookRowProps {
|
||||
@ -33,7 +33,7 @@ export const OrderbookRow = React.memo(
|
||||
<Vol value={bid} relativeValue={relativeBidVol} type="bid" />
|
||||
<PriceCell
|
||||
value={BigInt(price)}
|
||||
valueFormatted={formatNumber(price, decimalPlaces)}
|
||||
valueFormatted={addDecimalsFormatNumber(price, decimalPlaces)}
|
||||
/>
|
||||
<Vol value={ask} relativeValue={relativeAskVol} type="ask" />
|
||||
<CumulativeVol
|
||||
|
@ -1,6 +1,10 @@
|
||||
import { forwardRef } from 'react';
|
||||
import type { ValueFormatterParams } from 'ag-grid-community';
|
||||
import { PriceFlashCell, formatNumber, t } from '@vegaprotocol/react-helpers';
|
||||
import {
|
||||
PriceFlashCell,
|
||||
addDecimalsFormatNumber,
|
||||
t,
|
||||
} from '@vegaprotocol/react-helpers';
|
||||
import { AgGridDynamic as AgGrid } from '@vegaprotocol/ui-toolkit';
|
||||
import type {
|
||||
Markets_markets,
|
||||
@ -60,7 +64,7 @@ export const MarketListTable = forwardRef<AgGridReact, MarketListTableProps>(
|
||||
type="rightAligned"
|
||||
cellRenderer="PriceFlashCell"
|
||||
valueFormatter={({ value, data }: ValueFormatterParams) =>
|
||||
formatNumber(value, data.decimalPlaces)
|
||||
addDecimalsFormatNumber(value, data.decimalPlaces)
|
||||
}
|
||||
/>
|
||||
<AgGridColumn
|
||||
@ -68,7 +72,7 @@ export const MarketListTable = forwardRef<AgGridReact, MarketListTableProps>(
|
||||
field="data.bestOfferPrice"
|
||||
type="rightAligned"
|
||||
valueFormatter={({ value, data }: ValueFormatterParams) =>
|
||||
formatNumber(value, data.decimalPlaces)
|
||||
addDecimalsFormatNumber(value, data.decimalPlaces)
|
||||
}
|
||||
cellRenderer="PriceFlashCell"
|
||||
/>
|
||||
@ -78,7 +82,7 @@ export const MarketListTable = forwardRef<AgGridReact, MarketListTableProps>(
|
||||
type="rightAligned"
|
||||
cellRenderer="PriceFlashCell"
|
||||
valueFormatter={({ value, data }: ValueFormatterParams) =>
|
||||
formatNumber(value, data.decimalPlaces)
|
||||
addDecimalsFormatNumber(value, data.decimalPlaces)
|
||||
}
|
||||
/>
|
||||
<AgGridColumn headerName={t('Description')} field="name" />
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { formatNumber, t } from '@vegaprotocol/react-helpers';
|
||||
import { addDecimalsFormatNumber, t } from '@vegaprotocol/react-helpers';
|
||||
import type { Stats as IStats, StatFields as IStatFields } from './types';
|
||||
|
||||
// Stats fields config. Keys will correspond to graphql queries when used, and values
|
||||
@ -60,7 +60,7 @@ export const statsFields: { [key in keyof IStats]: IStatFields[] } = {
|
||||
{
|
||||
title: t('Total staked'),
|
||||
formatter: (total: string) => {
|
||||
return formatNumber(total, 18, 2);
|
||||
return addDecimalsFormatNumber(total, 18, 2);
|
||||
},
|
||||
description: t('Sum of VEGA associated with a Vega key'),
|
||||
},
|
||||
|
@ -2,7 +2,7 @@ import { forwardRef } from 'react';
|
||||
import type { ValueFormatterParams } from 'ag-grid-community';
|
||||
import {
|
||||
PriceFlashCell,
|
||||
formatNumber,
|
||||
addDecimalsFormatNumber,
|
||||
volumePrefix,
|
||||
addDecimal,
|
||||
t,
|
||||
@ -100,7 +100,7 @@ export const PositionsTable = forwardRef<AgGridReact, PositionsTableProps>(
|
||||
value,
|
||||
data,
|
||||
}: PositionsTableValueFormatterParams) =>
|
||||
formatNumber(value, data.market.decimalPlaces)
|
||||
addDecimalsFormatNumber(value, data.market.decimalPlaces)
|
||||
}
|
||||
/>
|
||||
<AgGridColumn
|
||||
|
@ -27,12 +27,16 @@ export const getNumberFormat = memoize(
|
||||
})
|
||||
);
|
||||
|
||||
export const formatNumber = (
|
||||
export const formatNumber = (rawValue: string | number, formatDecimals = 0) => {
|
||||
return getNumberFormat(formatDecimals).format(Number(rawValue));
|
||||
};
|
||||
|
||||
export const addDecimalsFormatNumber = (
|
||||
rawValue: string | number,
|
||||
decimalPlaces: number,
|
||||
formatDecimals: number = decimalPlaces
|
||||
) => {
|
||||
const x = addDecimal(rawValue, decimalPlaces);
|
||||
|
||||
return getNumberFormat(formatDecimals).format(Number(x));
|
||||
return formatNumber(x, formatDecimals);
|
||||
};
|
||||
|
@ -4,7 +4,7 @@ import { forwardRef, useMemo } from 'react';
|
||||
import { AgGridDynamic as AgGrid } from '@vegaprotocol/ui-toolkit';
|
||||
import type { TradeFields } from './__generated__/TradeFields';
|
||||
import {
|
||||
formatNumber,
|
||||
addDecimalsFormatNumber,
|
||||
getDateTimeFormat,
|
||||
t,
|
||||
} from '@vegaprotocol/react-helpers';
|
||||
@ -67,7 +67,7 @@ export const TradesTable = forwardRef<AgGridReact, TradesTableProps>(
|
||||
field="price"
|
||||
cellClass={changeCellClass('price')}
|
||||
valueFormatter={({ value, data }: ValueFormatterParams) => {
|
||||
return formatNumber(value, data.market.decimalPlaces);
|
||||
return addDecimalsFormatNumber(value, data.market.decimalPlaces);
|
||||
}}
|
||||
/>
|
||||
<AgGridColumn
|
||||
|
@ -12,7 +12,7 @@ const props: KeyValueTableProps = {
|
||||
it('Renders the correct elements', () => {
|
||||
const { container } = render(
|
||||
<KeyValueTable {...props}>
|
||||
<KeyValueTableRow>
|
||||
<KeyValueTableRow inline={true}>
|
||||
<span>My label</span>
|
||||
<span>My value</span>
|
||||
</KeyValueTableRow>
|
||||
@ -38,10 +38,10 @@ it('Renders the correct elements', () => {
|
||||
expect(rows[1].children[1]).toHaveTextContent('My value 2');
|
||||
});
|
||||
|
||||
it('Applies numeric class if prop is passed', () => {
|
||||
it('Applies numeric class if prop is passed row not inline', () => {
|
||||
render(
|
||||
<KeyValueTable {...props} numerical={true}>
|
||||
<KeyValueTableRow>
|
||||
<KeyValueTableRow inline={false}>
|
||||
<span>My label</span>
|
||||
<span>My value</span>
|
||||
</KeyValueTableRow>
|
||||
@ -51,12 +51,35 @@ it('Applies numeric class if prop is passed', () => {
|
||||
expect(screen.getByTestId('key-value-table')).toHaveClass(
|
||||
'w-full border-collapse mb-8 [border-spacing:0] break-all'
|
||||
);
|
||||
|
||||
expect(screen.getByTestId('key-value-table-row')).toHaveClass(
|
||||
' flex gap-1 flex-wrap justify-between border-b first:border-t border-black dark:border-white flex-col items-start'
|
||||
);
|
||||
});
|
||||
|
||||
it('Applies numeric class if prop is passed row inline', () => {
|
||||
render(
|
||||
<KeyValueTable {...props} numerical={true}>
|
||||
<KeyValueTableRow inline={true}>
|
||||
<span>My label</span>
|
||||
<span>My value</span>
|
||||
</KeyValueTableRow>
|
||||
</KeyValueTable>
|
||||
);
|
||||
|
||||
expect(screen.getByTestId('key-value-table')).toHaveClass(
|
||||
'w-full border-collapse mb-8 [border-spacing:0] break-all'
|
||||
);
|
||||
|
||||
expect(screen.getByTestId('key-value-table-row')).toHaveClass(
|
||||
'flex gap-1 flex-wrap justify-between border-b first:border-t border-black dark:border-white flex-row items-center'
|
||||
);
|
||||
});
|
||||
|
||||
it('Applies muted class if prop is passed', () => {
|
||||
render(
|
||||
<KeyValueTable {...props} muted={true}>
|
||||
<KeyValueTableRow>
|
||||
<KeyValueTableRow inline={false}>
|
||||
<span>My label</span>
|
||||
<span>My value</span>
|
||||
</KeyValueTableRow>
|
||||
|
@ -62,6 +62,7 @@ export interface KeyValueTableRowProps
|
||||
className?: string;
|
||||
numerical?: boolean; // makes all values monospace
|
||||
muted?: boolean;
|
||||
inline?: boolean;
|
||||
}
|
||||
|
||||
export const KeyValueTableRow = ({
|
||||
@ -69,25 +70,28 @@ export const KeyValueTableRow = ({
|
||||
className,
|
||||
muted,
|
||||
numerical,
|
||||
inline = true,
|
||||
}: KeyValueTableRowProps) => {
|
||||
const dlClassName = classNames(
|
||||
'flex flex-wrap justify-between items-center border-b first:border-t border-black dark:border-white',
|
||||
'flex gap-1 flex-wrap justify-between border-b first:border-t border-black dark:border-white',
|
||||
{ 'flex-col items-start': !inline },
|
||||
{ 'flex-row items-center': inline },
|
||||
{
|
||||
'border-black/60 dark:border-white/60 first:[border-top:none] last:[border-bottom:none]':
|
||||
muted,
|
||||
},
|
||||
className
|
||||
);
|
||||
const dtClassName = `break-normal font-medium uppercase align-top p-4`;
|
||||
const dtClassName = `break-words font-medium uppercase align-top p-4 capitalize`;
|
||||
const ddClassName = classNames(
|
||||
'align-top p-4 text-black/60 dark:text-white/60 break-normal',
|
||||
'align-top p-4 text-black/60 dark:text-white/60 break-words',
|
||||
{
|
||||
'font-mono': numerical,
|
||||
}
|
||||
);
|
||||
|
||||
return (
|
||||
<dl className={dlClassName}>
|
||||
<dl className={dlClassName} data-testid="key-value-table-row">
|
||||
<dt className={dtClassName}>{children[0]}</dt>
|
||||
<dd className={ddClassName}>{children[1]}</dd>
|
||||
</dl>
|
||||
|
Loading…
Reference in New Issue
Block a user