feat(governance,markets,ui-toolkit): highlight successor market changes (#4449)

Co-authored-by: Joe <joe@vega.xyz>
This commit is contained in:
Sam Keen 2023-08-09 14:05:37 +01:00 committed by GitHub
parent 26d5a67604
commit 8d31510d5e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 652 additions and 95 deletions

View File

@ -730,6 +730,7 @@ context(
.getByTestId('key-value-table-row') .getByTestId('key-value-table-row')
.contains(heading) .contains(heading)
.parent() .parent()
.parent()
.siblings(); .siblings();
} }
} }

View File

@ -45,8 +45,10 @@ export const useMarketDataDialogStore = create<MarketDataDialogState>(
export const ProposalMarketData = ({ export const ProposalMarketData = ({
marketData, marketData,
parentMarketData,
}: { }: {
marketData: MarketInfoWithData; marketData: MarketInfoWithData;
parentMarketData?: MarketInfoWithData;
}) => { }) => {
const { t } = useTranslation(); const { t } = useTranslation();
const { isOpen, open, close } = useMarketDataDialogStore(); const { isOpen, open, close } = useMarketDataDialogStore();
@ -58,8 +60,21 @@ export const ProposalMarketData = ({
const settlementData = marketData.tradableInstrument.instrument.product const settlementData = marketData.tradableInstrument.instrument.product
.dataSourceSpecForSettlementData.data as DataSourceDefinition; .dataSourceSpecForSettlementData.data as DataSourceDefinition;
const parentSettlementData =
parentMarketData?.tradableInstrument.instrument?.product
?.dataSourceSpecForSettlementData?.data;
const terminationData = marketData.tradableInstrument.instrument.product const terminationData = marketData.tradableInstrument.instrument.product
.dataSourceSpecForTradingTermination.data as DataSourceDefinition; .dataSourceSpecForTradingTermination.data as DataSourceDefinition;
const parentTerminationData =
parentMarketData?.tradableInstrument.instrument?.product
?.dataSourceSpecForTradingTermination?.data;
const isParentSettlementDataEqual =
parentSettlementData !== undefined &&
isEqual(settlementData, parentSettlementData);
const isParentTerminationDataEqual =
parentTerminationData !== undefined &&
isEqual(terminationData, parentTerminationData);
const getSigners = (data: DataSourceDefinition) => { const getSigners = (data: DataSourceDefinition) => {
if (data.sourceType.__typename === 'DataSourceDefinitionExternal') { if (data.sourceType.__typename === 'DataSourceDefinitionExternal') {
@ -97,12 +112,22 @@ export const ProposalMarketData = ({
<AccordionItem <AccordionItem
itemId="key-details" itemId="key-details"
title={t('Key details')} title={t('Key details')}
content={<KeyDetailsInfoPanel market={marketData} />} content={
<KeyDetailsInfoPanel
market={marketData}
parentMarket={parentMarketData}
/>
}
/> />
<AccordionItem <AccordionItem
itemId="instrument" itemId="instrument"
title={t('Instrument')} title={t('Instrument')}
content={<InstrumentInfoPanel market={marketData} />} content={
<InstrumentInfoPanel
market={marketData}
parentMarket={parentMarketData}
/>
}
/> />
{isEqual( {isEqual(
getSigners(settlementData), getSigners(settlementData),
@ -115,6 +140,11 @@ export const ProposalMarketData = ({
<OracleInfoPanel <OracleInfoPanel
market={marketData} market={marketData}
type="settlementData" type="settlementData"
parentMarket={
isParentSettlementDataEqual
? undefined
: parentMarketData
}
/> />
} }
/> />
@ -127,6 +157,11 @@ export const ProposalMarketData = ({
<OracleInfoPanel <OracleInfoPanel
market={marketData} market={marketData}
type="settlementData" type="settlementData"
parentMarket={
isParentSettlementDataEqual
? undefined
: parentMarketData
}
/> />
} }
/> />
@ -135,11 +170,21 @@ export const ProposalMarketData = ({
itemId="termination-oracle" itemId="termination-oracle"
title={t('Termination Oracle')} title={t('Termination Oracle')}
content={ content={
<OracleInfoPanel market={marketData} type="termination" /> <OracleInfoPanel
market={marketData}
type="termination"
parentMarket={
isParentTerminationDataEqual
? undefined
: parentMarketData
}
/>
} }
/> />
</> </>
)} )}
{/*Note: successor markets will not differ in their settlement*/}
{/*assets, so no need to pass in parent market data for comparison.*/}
<AccordionItem <AccordionItem
itemId="settlement-asset" itemId="settlement-asset"
title={t('Settlement asset')} title={t('Settlement asset')}
@ -148,22 +193,42 @@ export const ProposalMarketData = ({
<AccordionItem <AccordionItem
itemId="metadata" itemId="metadata"
title={t('Metadata')} title={t('Metadata')}
content={<MetadataInfoPanel market={marketData} />} content={
<MetadataInfoPanel
market={marketData}
parentMarket={parentMarketData}
/>
}
/> />
<AccordionItem <AccordionItem
itemId="risk-model" itemId="risk-model"
title={t('Risk model')} title={t('Risk model')}
content={<RiskModelInfoPanel market={marketData} />} content={
<RiskModelInfoPanel
market={marketData}
parentMarket={parentMarketData}
/>
}
/> />
<AccordionItem <AccordionItem
itemId="risk-parameters" itemId="risk-parameters"
title={t('Risk parameters')} title={t('Risk parameters')}
content={<RiskParametersInfoPanel market={marketData} />} content={
<RiskParametersInfoPanel
market={marketData}
parentMarket={parentMarketData}
/>
}
/> />
<AccordionItem <AccordionItem
itemId="risk-factors" itemId="risk-factors"
title={t('Risk factors')} title={t('Risk factors')}
content={<RiskFactorsInfoPanel market={marketData} />} content={
<RiskFactorsInfoPanel
market={marketData}
parentMarket={parentMarketData}
/>
}
/> />
{( {(
marketData.priceMonitoringSettings?.parameters?.triggers || [] marketData.priceMonitoringSettings?.parameters?.triggers || []
@ -174,6 +239,7 @@ export const ProposalMarketData = ({
content={ content={
<PriceMonitoringBoundsInfoPanel <PriceMonitoringBoundsInfoPanel
market={marketData} market={marketData}
parentMarket={parentMarketData}
triggerIndex={triggerIndex} triggerIndex={triggerIndex}
/> />
} }
@ -183,13 +249,21 @@ export const ProposalMarketData = ({
itemId="liqudity-monitoring-parameters" itemId="liqudity-monitoring-parameters"
title={t('Liquidity monitoring parameters')} title={t('Liquidity monitoring parameters')}
content={ content={
<LiquidityMonitoringParametersInfoPanel market={marketData} /> <LiquidityMonitoringParametersInfoPanel
market={marketData}
parentMarket={parentMarketData}
/>
} }
/> />
<AccordionItem <AccordionItem
itemId="liquidity-price-range" itemId="liquidity-price-range"
title={t('Liquidity price range')} title={t('Liquidity price range')}
content={<LiquidityPriceRangeInfoPanel market={marketData} />} content={
<LiquidityPriceRangeInfoPanel
market={marketData}
parentMarket={parentMarketData}
/>
}
/> />
</Accordion> </Accordion>
</div> </div>

View File

@ -32,6 +32,7 @@ export interface ProposalProps {
proposal: ProposalFieldsFragment | ProposalQuery['proposal']; proposal: ProposalFieldsFragment | ProposalQuery['proposal'];
networkParams: Partial<NetworkParamsResult>; networkParams: Partial<NetworkParamsResult>;
newMarketData?: MarketInfoWithData | null; newMarketData?: MarketInfoWithData | null;
parentMarketData?: MarketInfoWithData | null;
assetData?: AssetQuery | null; assetData?: AssetQuery | null;
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
restData: any; restData: any;
@ -46,6 +47,7 @@ export const Proposal = ({
networkParams, networkParams,
restData, restData,
newMarketData, newMarketData,
parentMarketData,
assetData, assetData,
originalMarketProposalRestData, originalMarketProposalRestData,
mostRecentlyEnactedAssociatedMarketProposal, mostRecentlyEnactedAssociatedMarketProposal,
@ -157,7 +159,10 @@ export const Proposal = ({
{newMarketData && ( {newMarketData && (
<div className="mb-4"> <div className="mb-4">
<ProposalMarketData marketData={newMarketData} /> <ProposalMarketData
marketData={newMarketData}
parentMarketData={parentMarketData ? parentMarketData : undefined}
/>
</div> </div>
)} )}

View File

@ -14,6 +14,9 @@ import {
NetworkParams, NetworkParams,
useNetworkParams, useNetworkParams,
} from '@vegaprotocol/network-parameters'; } from '@vegaprotocol/network-parameters';
import { useParentMarketIdQuery } from '@vegaprotocol/markets';
import { FLAGS } from '@vegaprotocol/environment';
import { useSuccessorMarketProposalDetails } from '@vegaprotocol/proposals';
export const ProposalContainer = () => { export const ProposalContainer = () => {
const [ const [
@ -54,6 +57,10 @@ export const ProposalContainer = () => {
skip: !params.proposalId, skip: !params.proposalId,
}); });
const successor = useSuccessorMarketProposalDetails(params.proposalId);
const isSuccessor = !!successor?.parentMarketId || !!successor.code;
const { const {
state: { state: {
data: originalMarketProposalRestData, data: originalMarketProposalRestData,
@ -96,6 +103,36 @@ export const ProposalContainer = () => {
}, },
}); });
const {
data: parentMarketId,
loading: parentMarketIdLoading,
error: parentMarketIdError,
} = useParentMarketIdQuery({
variables: {
marketId: newMarketData?.data?.market?.id || '',
},
skip:
!FLAGS.SUCCESSOR_MARKETS ||
!isSuccessor ||
!newMarketData?.data?.market?.id,
});
const {
data: parentMarketData,
loading: parentMarketLoading,
error: parentMarketError,
} = useDataProvider({
dataProvider: marketInfoWithDataProvider,
skipUpdates: true,
variables: {
marketId: parentMarketId?.market?.parentMarketID || '',
skip:
!FLAGS.SUCCESSOR_MARKETS ||
!isSuccessor ||
!parentMarketId?.market?.parentMarketID,
},
});
const { const {
data: assetData, data: assetData,
loading: assetLoading, loading: assetLoading,
@ -160,6 +197,8 @@ export const ProposalContainer = () => {
newMarketLoading || newMarketLoading ||
assetLoading || assetLoading ||
networkParamsLoading || networkParamsLoading ||
parentMarketIdLoading ||
parentMarketLoading ||
(restLoading ? (restLoading as boolean) : false) || (restLoading ? (restLoading as boolean) : false) ||
(originalMarketProposalRestLoading (originalMarketProposalRestLoading
? (originalMarketProposalRestLoading as boolean) ? (originalMarketProposalRestLoading as boolean)
@ -172,15 +211,18 @@ export const ProposalContainer = () => {
error || error ||
newMarketError || newMarketError ||
assetError || assetError ||
networkParamsError ||
parentMarketIdError ||
parentMarketError ||
restError || restError ||
originalMarketProposalRestError || originalMarketProposalRestError ||
previouslyEnactedMarketProposalsRestError || previouslyEnactedMarketProposalsRestError
networkParamsError
} }
data={{ data={{
...data, ...data,
...networkParams, ...networkParams,
...(newMarketData ? { newMarketData } : {}), ...(newMarketData ? { newMarketData } : {}),
...(parentMarketData ? { parentMarketData } : {}),
...(assetData ? { assetData } : {}), ...(assetData ? { assetData } : {}),
...(restData ? { restData } : {}), ...(restData ? { restData } : {}),
...(originalMarketProposalRestData ...(originalMarketProposalRestData
@ -197,6 +239,7 @@ export const ProposalContainer = () => {
networkParams={networkParams} networkParams={networkParams}
restData={restData} restData={restData}
newMarketData={newMarketData} newMarketData={newMarketData}
parentMarketData={parentMarketData}
assetData={assetData} assetData={assetData}
originalMarketProposalRestData={originalMarketProposalRestData} originalMarketProposalRestData={originalMarketProposalRestData}
mostRecentlyEnactedAssociatedMarketProposal={ mostRecentlyEnactedAssociatedMarketProposal={

View File

@ -28,10 +28,10 @@ export const assetProvider = makeDataProvider<
getData, getData,
}); });
export const useAssetDataProvider = (assetId: string) => { export const useAssetDataProvider = (assetId: string, skip?: boolean) => {
return useDataProvider({ return useDataProvider({
dataProvider: assetProvider, dataProvider: assetProvider,
variables: { assetId: assetId || '' }, variables: { assetId: assetId || '' },
skip: !assetId, skip: !assetId || skip,
}); });
}; };

View File

@ -4,8 +4,10 @@ import {
} from '@vegaprotocol/utils'; } from '@vegaprotocol/utils';
import { t } from '@vegaprotocol/i18n'; import { t } from '@vegaprotocol/i18n';
import { import {
Intent,
KeyValueTable, KeyValueTable,
KeyValueTableRow, KeyValueTableRow,
Lozenge,
Tooltip, Tooltip,
} from '@vegaprotocol/ui-toolkit'; } from '@vegaprotocol/ui-toolkit';
import BigNumber from 'bignumber.js'; import BigNumber from 'bignumber.js';
@ -22,9 +24,11 @@ interface RowProps {
unformatted?: boolean; unformatted?: boolean;
assetSymbol?: string; assetSymbol?: string;
noBorder?: boolean; noBorder?: boolean;
parentValue?: ReactNode;
hasParentData?: boolean;
} }
const Row = ({ export const Row = ({
field, field,
value, value,
decimalPlaces, decimalPlaces,
@ -32,7 +36,14 @@ const Row = ({
unformatted, unformatted,
assetSymbol = '', assetSymbol = '',
noBorder = true, noBorder = true,
parentValue,
hasParentData,
}: RowProps) => { }: RowProps) => {
// Note: we need both 'parentValue' and 'hasParentData' to do a conditional
// check to differentiate between when parentData itself is missing and when
// a specific parentValue is missing. These values are only used when we
// have successor market parent data.
const className = 'text-sm'; const className = 'text-sm';
const getFormattedValue = (value: ReactNode) => { const getFormattedValue = (value: ReactNode) => {
@ -55,6 +66,10 @@ const Row = ({
const formattedValue = getFormattedValue(value); const formattedValue = getFormattedValue(value);
if (!formattedValue) return null; if (!formattedValue) return null;
const newValueInSuccessorMarket = hasParentData && value && !parentValue;
const valueDiffersFromParentMarket = parentValue && parentValue !== value;
return ( return (
<KeyValueTableRow <KeyValueTableRow
key={field} key={field}
@ -63,10 +78,35 @@ const Row = ({
dtClassName={className} dtClassName={className}
ddClassName={className} ddClassName={className}
> >
<Tooltip description={tooltipMapping[field]} align="start"> <div className="flex items-center gap-3">
<div tabIndex={-1}>{startCase(t(field))}</div> <Tooltip description={tooltipMapping[field]} align="start">
</Tooltip> <div tabIndex={-1}>{startCase(t(field))}</div>
<span style={{ wordBreak: 'break-word' }}>{formattedValue}</span> </Tooltip>
{valueDiffersFromParentMarket && (
<Lozenge className="py-0" variant={Intent.Primary}>
{t('Updated')}
</Lozenge>
)}
{newValueInSuccessorMarket && (
<Lozenge className="py-0" variant={Intent.Primary}>
{t('Added')}
</Lozenge>
)}
</div>
<div style={{ wordBreak: 'break-word' }}>
{valueDiffersFromParentMarket ? (
<div className="flex items-center gap-3">
<span className="line-through">
{getFormattedValue(parentValue)}
</span>
<span>{formattedValue}</span>
</div>
) : (
formattedValue
)}
</div>
</KeyValueTableRow> </KeyValueTableRow>
); );
}; };
@ -79,6 +119,7 @@ export interface MarketInfoTableProps {
children?: ReactNode; children?: ReactNode;
assetSymbol?: string; assetSymbol?: string;
noBorder?: boolean; noBorder?: boolean;
parentData?: Record<string, ReactNode> | null | undefined;
} }
export const MarketInfoTable = ({ export const MarketInfoTable = ({
@ -89,25 +130,33 @@ export const MarketInfoTable = ({
children, children,
assetSymbol, assetSymbol,
noBorder, noBorder,
parentData,
}: MarketInfoTableProps) => { }: MarketInfoTableProps) => {
if (!data || typeof data !== 'object') { if (!data || typeof data !== 'object') {
return null; return null;
} }
const hasParentData = parentData !== undefined;
return ( return (
<> <>
<KeyValueTable> <KeyValueTable>
{Object.entries(data).map(([key, value]) => ( <>
<Row {Object.entries(data).map(([key, value]) => (
key={key} <Row
field={key} key={key}
value={value} field={key}
decimalPlaces={decimalPlaces} value={value}
assetSymbol={assetSymbol} decimalPlaces={decimalPlaces}
asPercentage={asPercentage} assetSymbol={assetSymbol}
unformatted={unformatted} asPercentage={asPercentage}
noBorder={noBorder} unformatted={unformatted}
/> noBorder={noBorder}
))} parentValue={parentData?.[key]}
hasParentData={hasParentData}
/>
))}
</>
</KeyValueTable> </KeyValueTable>
<div className="flex flex-col gap-2">{children}</div> <div className="flex flex-col gap-2">{children}</div>
</> </>

View File

@ -1,3 +1,4 @@
import isEqual from 'lodash/isEqual';
import type { ReactNode } from 'react'; import type { ReactNode } from 'react';
import { Fragment, useState } from 'react'; import { Fragment, useState } from 'react';
import { useMemo } from 'react'; import { useMemo } from 'react';
@ -47,11 +48,14 @@ import {
useSuccessorMarketQuery, useSuccessorMarketQuery,
} from '../../__generated__'; } from '../../__generated__';
import { useSuccessorMarketProposalDetailsQuery } from '@vegaprotocol/proposals'; import { useSuccessorMarketProposalDetailsQuery } from '@vegaprotocol/proposals';
import type { MarketTradingMode } from '@vegaprotocol/types';
import type { Signer } from '@vegaprotocol/types';
import classNames from 'classnames'; import classNames from 'classnames';
import compact from 'lodash/compact'; import compact from 'lodash/compact';
type MarketInfoProps = { type MarketInfoProps = {
market: MarketInfo; market: MarketInfo;
parentMarket?: MarketInfo;
children?: ReactNode; children?: ReactNode;
}; };
@ -156,21 +160,43 @@ export const InsurancePoolInfoPanel = ({
); );
}; };
export const KeyDetailsInfoPanel = ({ market }: MarketInfoProps) => { export const KeyDetailsInfoPanel = ({
const { data: parentData } = useParentMarketIdQuery({ market,
parentMarket,
}: MarketInfoProps) => {
const { data: parentMarketIdData } = useParentMarketIdQuery({
variables: { variables: {
marketId: market.id, marketId: market.id,
}, },
skip: !FLAGS.SUCCESSOR_MARKETS, skip: !FLAGS.SUCCESSOR_MARKETS,
}); });
const { data: successor } = useSuccessorMarketProposalDetailsQuery({ const { data: successorProposalDetails } =
useSuccessorMarketProposalDetailsQuery({
variables: {
proposalId: market.proposal?.id || '',
},
skip: !FLAGS.SUCCESSOR_MARKETS || !market.proposal?.id,
});
// The following queries are needed as the parent market could also have been a successor market.
// Note: the parent market is only passed to this component if the successor markets flag is enabled,
// so that check is not needed in the skip.
const { data: grandparentMarketIdData } = useParentMarketIdQuery({
variables: { variables: {
proposalId: market.proposal?.id || '', marketId: parentMarket?.id || '',
}, },
skip: !FLAGS.SUCCESSOR_MARKETS || !market.proposal?.id, skip: !parentMarket?.id,
}); });
const { data: parentSuccessorProposalDetails } =
useSuccessorMarketProposalDetailsQuery({
variables: {
proposalId: parentMarket?.proposal?.id || '',
},
skip: !parentMarket?.proposal?.id,
});
const assetDecimals = const assetDecimals =
market.tradableInstrument.instrument.product.settlementAsset.decimals; market.tradableInstrument.instrument.product.settlementAsset.decimals;
@ -181,11 +207,12 @@ export const KeyDetailsInfoPanel = ({ market }: MarketInfoProps) => {
? { ? {
name: market.tradableInstrument.instrument.name, name: market.tradableInstrument.instrument.name,
marketID: market.id, marketID: market.id,
parentMarketID: parentData?.market?.parentMarketID || '-', parentMarketID: parentMarketIdData?.market?.parentMarketID || '-',
insurancePoolFraction: insurancePoolFraction:
(successor?.proposal?.terms.change.__typename === 'NewMarket' && (successorProposalDetails?.proposal?.terms.change.__typename ===
successor.proposal.terms.change.successorConfiguration 'NewMarket' &&
?.insurancePoolFraction) || successorProposalDetails.proposal.terms.change
.successorConfiguration?.insurancePoolFraction) ||
'-', '-',
tradingMode: tradingMode:
market.tradingMode && market.tradingMode &&
@ -205,6 +232,28 @@ export const KeyDetailsInfoPanel = ({ market }: MarketInfoProps) => {
settlementAssetDecimalPlaces: assetDecimals, settlementAssetDecimalPlaces: assetDecimals,
} }
} }
parentData={
parentMarket && {
name: parentMarket?.tradableInstrument?.instrument?.name,
marketID: parentMarket?.id,
parentMarketID: grandparentMarketIdData?.market?.parentMarketID,
insurancePoolFraction:
parentSuccessorProposalDetails?.proposal?.terms.change
.__typename === 'NewMarket' &&
parentSuccessorProposalDetails.proposal.terms.change
.successorConfiguration?.insurancePoolFraction,
tradingMode:
parentMarket?.tradingMode &&
MarketTradingModeMapping[
parentMarket.tradingMode as MarketTradingMode
],
marketDecimalPlaces: parentMarket?.decimalPlaces,
positionDecimalPlaces: parentMarket?.positionDecimalPlaces,
settlementAssetDecimalPlaces:
parentMarket?.tradableInstrument?.instrument?.product
?.settlementAsset?.decimals,
}
}
/> />
); );
}; };
@ -329,7 +378,10 @@ export const SuccessionLineInfoPanel = ({
); );
}; };
export const InstrumentInfoPanel = ({ market }: MarketInfoProps) => ( export const InstrumentInfoPanel = ({
market,
parentMarket,
}: MarketInfoProps) => (
<MarketInfoTable <MarketInfoTable
data={{ data={{
marketName: market.tradableInstrument.instrument.name, marketName: market.tradableInstrument.instrument.name,
@ -337,6 +389,16 @@ export const InstrumentInfoPanel = ({ market }: MarketInfoProps) => (
productType: market.tradableInstrument.instrument.product.__typename, productType: market.tradableInstrument.instrument.product.__typename,
quoteName: market.tradableInstrument.instrument.product.quoteName, quoteName: market.tradableInstrument.instrument.product.quoteName,
}} }}
parentData={
parentMarket && {
marketName: parentMarket?.tradableInstrument?.instrument?.name,
code: parentMarket?.tradableInstrument?.instrument?.code,
productType:
parentMarket?.tradableInstrument?.instrument?.product?.__typename,
quoteName:
parentMarket?.tradableInstrument?.instrument?.product?.quoteName,
}
}
/> />
); );
@ -349,6 +411,7 @@ export const SettlementAssetInfoPanel = ({ market }: MarketInfoProps) => {
() => market?.tradableInstrument.instrument.product?.settlementAsset.id, () => market?.tradableInstrument.instrument.product?.settlementAsset.id,
[market] [market]
); );
const { data: asset } = useAssetDataProvider(assetId ?? ''); const { data: asset } = useAssetDataProvider(assetId ?? '');
return asset ? ( return asset ? (
<> <>
@ -371,54 +434,148 @@ export const SettlementAssetInfoPanel = ({ market }: MarketInfoProps) => {
); );
}; };
export const MetadataInfoPanel = ({ market }: MarketInfoProps) => ( const getMarketMetadata = (market: MarketInfo) =>
market.tradableInstrument.instrument.metadata.tags
?.map((tag) => {
const [key, value] = tag.split(':');
return { [key]: value };
})
.reduce((acc, curr) => ({ ...acc, ...curr }), {});
export const MetadataInfoPanel = ({
market,
parentMarket,
}: MarketInfoProps) => (
<MarketInfoTable <MarketInfoTable
data={{ data={{
expiryDate: getMarketExpiryDateFormatted( expiryDate: getMarketExpiryDateFormatted(
market.tradableInstrument.instrument.metadata.tags market.tradableInstrument.instrument.metadata.tags
), ),
...market.tradableInstrument.instrument.metadata.tags ...(getMarketMetadata(market) || {}),
?.map((tag) => {
const [key, value] = tag.split(':');
return { [key]: value };
})
.reduce((acc, curr) => ({ ...acc, ...curr }), {}),
}} }}
parentData={
parentMarket && {
expiryDate: getMarketExpiryDateFormatted(
parentMarket.tradableInstrument.instrument.metadata.tags
),
...(getMarketMetadata(parentMarket) || {}),
}
}
/> />
); );
export const RiskModelInfoPanel = ({ market }: MarketInfoProps) => { export const RiskModelInfoPanel = ({
market,
parentMarket,
}: MarketInfoProps) => {
if (market.tradableInstrument.riskModel.__typename !== 'LogNormalRiskModel') { if (market.tradableInstrument.riskModel.__typename !== 'LogNormalRiskModel') {
return null; return null;
} }
const { tau, riskAversionParameter } = market.tradableInstrument.riskModel; const { tau, riskAversionParameter } = market.tradableInstrument.riskModel;
return <MarketInfoTable data={{ tau, riskAversionParameter }} unformatted />;
let parentData;
if (
parentMarket?.tradableInstrument?.riskModel?.__typename ===
'LogNormalRiskModel'
) {
const {
tau: parentTau,
riskAversionParameter: parentRiskAversionParameter,
} = market.tradableInstrument.riskModel;
parentData = {
tau: parentTau,
riskAversionParameter: parentRiskAversionParameter,
};
}
return (
<MarketInfoTable
data={{ tau, riskAversionParameter }}
parentData={parentData}
unformatted
/>
);
}; };
export const RiskParametersInfoPanel = ({ market }: MarketInfoProps) => { export const RiskParametersInfoPanel = ({
if (market.tradableInstrument.riskModel.__typename === 'LogNormalRiskModel') { market,
parentMarket,
}: MarketInfoProps) => {
const marketType = market.tradableInstrument.riskModel.__typename;
let data, parentData;
if (marketType === 'LogNormalRiskModel') {
const { r, sigma, mu } = market.tradableInstrument.riskModel.params; const { r, sigma, mu } = market.tradableInstrument.riskModel.params;
return <MarketInfoTable data={{ r, sigma, mu }} unformatted />; data = { r, sigma, mu };
}
if (market.tradableInstrument.riskModel.__typename === 'SimpleRiskModel') { if (
parentMarket?.tradableInstrument?.riskModel.__typename ===
'LogNormalRiskModel'
) {
const parentParams = parentMarket.tradableInstrument.riskModel.params;
parentData = {
r: parentParams.r,
sigma: parentParams.sigma,
mu: parentParams.mu,
};
}
} else if (marketType === 'SimpleRiskModel') {
const { factorLong, factorShort } = const { factorLong, factorShort } =
market.tradableInstrument.riskModel.params; market.tradableInstrument.riskModel.params;
return <MarketInfoTable data={{ factorLong, factorShort }} unformatted />; data = { factorLong, factorShort };
if (
parentMarket?.tradableInstrument?.riskModel.__typename ===
'SimpleRiskModel'
) {
const parentParams = parentMarket.tradableInstrument.riskModel.params;
parentData = {
factorLong: parentParams.factorLong,
factorShort: parentParams.factorShort,
};
}
} }
return null;
if (!data) return null;
return <MarketInfoTable data={data} parentData={parentData} unformatted />;
}; };
export const RiskFactorsInfoPanel = ({ market }: MarketInfoProps) => { export const RiskFactorsInfoPanel = ({
market,
parentMarket,
}: MarketInfoProps) => {
if (!market.riskFactors) { if (!market.riskFactors) {
return null; return null;
} }
const { short, long } = market.riskFactors; const { short, long } = market.riskFactors;
return <MarketInfoTable data={{ short, long }} unformatted />;
let parentData;
if (parentMarket?.riskFactors) {
const parentShort = parentMarket.riskFactors.short;
const parentLong = parentMarket.riskFactors.long;
parentData = { short: parentShort, long: parentLong };
}
return (
<MarketInfoTable
data={{ short, long }}
parentData={parentData}
unformatted
/>
);
}; };
export const PriceMonitoringBoundsInfoPanel = ({ export const PriceMonitoringBoundsInfoPanel = ({
market, market,
triggerIndex, triggerIndex,
parentMarket,
}: MarketInfoProps & { }: MarketInfoProps & {
triggerIndex: number; triggerIndex: number;
}) => { }) => {
@ -426,11 +583,35 @@ export const PriceMonitoringBoundsInfoPanel = ({
dataProvider: marketDataProvider, dataProvider: marketDataProvider,
variables: { marketId: market.id }, variables: { marketId: market.id },
}); });
const { data: parentData } = useDataProvider({
dataProvider: marketDataProvider,
variables: { marketId: parentMarket?.id || '' },
skip:
!parentMarket ||
!parentMarket?.priceMonitoringSettings?.parameters?.triggers?.[
triggerIndex
],
});
const quoteUnit = const quoteUnit =
market?.tradableInstrument.instrument.product?.quoteName || ''; market?.tradableInstrument.instrument.product?.quoteName || '';
const parentQuoteUnit =
parentMarket?.tradableInstrument.instrument.product?.quoteName || '';
const isParentQuoteUnitEqual = quoteUnit === parentQuoteUnit;
const trigger = const trigger =
market.priceMonitoringSettings?.parameters?.triggers?.[triggerIndex]; market.priceMonitoringSettings?.parameters?.triggers?.[triggerIndex];
const parentTrigger =
parentMarket?.priceMonitoringSettings?.parameters?.triggers?.[triggerIndex];
const isParentTriggerEqual = isEqual(trigger, parentTrigger);
const bounds = data?.priceMonitoringBounds?.[triggerIndex]; const bounds = data?.priceMonitoringBounds?.[triggerIndex];
const parentBounds = parentData?.priceMonitoringBounds?.[triggerIndex];
const shouldShowParentData =
isParentQuoteUnitEqual && isParentTriggerEqual && !!parentBounds;
if (!trigger) { if (!trigger) {
console.error( console.error(
`Could not find data for trigger ${triggerIndex} (market id: ${market.id})` `Could not find data for trigger ${triggerIndex} (market id: ${market.id})`
@ -457,6 +638,14 @@ export const PriceMonitoringBoundsInfoPanel = ({
highestPrice: bounds.maxValidPrice, highestPrice: bounds.maxValidPrice,
lowestPrice: bounds.minValidPrice, lowestPrice: bounds.minValidPrice,
}} }}
parentData={
shouldShowParentData
? {
highestPrice: parentBounds.maxValidPrice,
lowestPrice: parentBounds.minValidPrice,
}
: undefined
}
decimalPlaces={market.decimalPlaces} decimalPlaces={market.decimalPlaces}
assetSymbol={quoteUnit} assetSymbol={quoteUnit}
/> />
@ -472,18 +661,31 @@ export const PriceMonitoringBoundsInfoPanel = ({
export const LiquidityMonitoringParametersInfoPanel = ({ export const LiquidityMonitoringParametersInfoPanel = ({
market, market,
}: MarketInfoProps) => ( parentMarket,
<MarketInfoTable }: MarketInfoProps) => {
data={{ const marketData = {
triggeringRatio: market.liquidityMonitoringParameters.triggeringRatio, triggeringRatio: market.liquidityMonitoringParameters.triggeringRatio,
timeWindow: timeWindow:
market.liquidityMonitoringParameters.targetStakeParameters.timeWindow, market.liquidityMonitoringParameters.targetStakeParameters.timeWindow,
scalingFactor: scalingFactor:
market.liquidityMonitoringParameters.targetStakeParameters market.liquidityMonitoringParameters.targetStakeParameters.scalingFactor,
.scalingFactor, };
}}
/> const parentMarketData = parentMarket
); ? {
triggeringRatio:
parentMarket.liquidityMonitoringParameters.triggeringRatio,
timeWindow:
parentMarket.liquidityMonitoringParameters.targetStakeParameters
.timeWindow,
scalingFactor:
parentMarket.liquidityMonitoringParameters.targetStakeParameters
.scalingFactor,
}
: {};
return <MarketInfoTable data={marketData} parentData={parentMarketData} />;
};
export const LiquidityInfoPanel = ({ market, children }: MarketInfoProps) => { export const LiquidityInfoPanel = ({ market, children }: MarketInfoProps) => {
const assetDecimals = const assetDecimals =
@ -510,16 +712,61 @@ export const LiquidityInfoPanel = ({ market, children }: MarketInfoProps) => {
); );
}; };
export const LiquidityPriceRangeInfoPanel = ({ market }: MarketInfoProps) => { export const LiquidityPriceRangeInfoPanel = ({
market,
parentMarket,
}: MarketInfoProps) => {
const quoteUnit = const quoteUnit =
market?.tradableInstrument.instrument.product?.quoteName || ''; market?.tradableInstrument.instrument.product?.quoteName || '';
const parentQuoteUnit =
parentMarket?.tradableInstrument.instrument.product?.quoteName || '';
const liquidityPriceRange = formatNumberPercentage( const liquidityPriceRange = formatNumberPercentage(
new BigNumber(market.lpPriceRange).times(100) new BigNumber(market.lpPriceRange).times(100)
); );
const parentLiquidityPriceRange = parentMarket
? formatNumberPercentage(
new BigNumber(parentMarket.lpPriceRange).times(100)
)
: null;
const { data } = useDataProvider({ const { data } = useDataProvider({
dataProvider: marketDataProvider, dataProvider: marketDataProvider,
variables: { marketId: market.id }, variables: { marketId: market.id },
}); });
const { data: parentMarketData } = useDataProvider({
dataProvider: marketDataProvider,
variables: { marketId: parentMarket?.id || '' },
skip: !parentMarket,
});
let parentData;
if (parentMarket && parentMarketData && quoteUnit === parentQuoteUnit) {
parentData = {
liquidityPriceRange: `${parentLiquidityPriceRange} of mid price`,
lowestPrice:
parentMarketData?.midPrice &&
`${addDecimalsFormatNumber(
new BigNumber(1)
.minus(parentMarket.lpPriceRange)
.times(parentMarketData.midPrice)
.toString(),
parentMarket.decimalPlaces
)} ${quoteUnit}`,
highestPrice:
parentMarketData?.midPrice &&
`${addDecimalsFormatNumber(
new BigNumber(1)
.plus(parentMarket.lpPriceRange)
.times(parentMarketData.midPrice)
.toString(),
parentMarket.decimalPlaces
)} ${quoteUnit}`,
};
}
return ( return (
<> <>
<p className="text-sm mb-2"> <p className="text-sm mb-2">
@ -552,6 +799,7 @@ export const LiquidityPriceRangeInfoPanel = ({ market }: MarketInfoProps) => {
market.decimalPlaces market.decimalPlaces
)} ${quoteUnit}`, )} ${quoteUnit}`,
}} }}
parentData={parentData}
/> />
</> </>
); );
@ -560,8 +808,12 @@ export const LiquidityPriceRangeInfoPanel = ({ market }: MarketInfoProps) => {
export const OracleInfoPanel = ({ export const OracleInfoPanel = ({
market, market,
type, type,
parentMarket,
}: MarketInfoProps & { type: 'settlementData' | 'termination' }) => { }: MarketInfoProps & { type: 'settlementData' | 'termination' }) => {
// If this is a successor market, this component will only receive parent market
// data if the termination or settlement data is different from the parent.
const product = market.tradableInstrument.instrument.product; const product = market.tradableInstrument.instrument.product;
const parentProduct = parentMarket?.tradableInstrument?.instrument?.product;
const { VEGA_EXPLORER_URL, ORACLE_PROOFS_URL } = useEnvironment(); const { VEGA_EXPLORER_URL, ORACLE_PROOFS_URL } = useEnvironment();
const { data } = useOracleProofs(ORACLE_PROOFS_URL); const { data } = useOracleProofs(ORACLE_PROOFS_URL);
@ -570,12 +822,33 @@ export const OracleInfoPanel = ({
? product.dataSourceSpecForSettlementData.id ? product.dataSourceSpecForSettlementData.id
: product.dataSourceSpecForTradingTermination.id; : product.dataSourceSpecForTradingTermination.id;
const parentDataSourceSpecId =
type === 'settlementData'
? parentProduct?.dataSourceSpecForSettlementData?.id
: parentProduct?.dataSourceSpecForTradingTermination?.id;
const dataSourceSpec = ( const dataSourceSpec = (
type === 'settlementData' type === 'settlementData'
? product.dataSourceSpecForSettlementData.data ? product.dataSourceSpecForSettlementData.data
: product.dataSourceSpecForTradingTermination.data : product.dataSourceSpecForTradingTermination.data
) as DataSourceDefinition; ) as DataSourceDefinition;
const parentDataSourceSpec =
type === 'settlementData'
? parentProduct?.dataSourceSpecForSettlementData?.data
: (parentProduct?.dataSourceSpecForTradingTermination
?.data as DataSourceDefinition);
const isParentDataSourceSpecEqual =
parentDataSourceSpec !== undefined &&
dataSourceSpec === parentDataSourceSpec;
const isParentDataSourceSpecIdEqual =
parentDataSourceSpecId !== undefined &&
dataSourceSpecId === parentDataSourceSpecId;
// We'll only provide successor parent data (if it differs) to the
// DataSourceProof component. Having an old external link struck through
// is unlikely to be useful.
return ( return (
<div className="flex flex-col gap-2"> <div className="flex flex-col gap-2">
<DataSourceProof <DataSourceProof
@ -584,7 +857,14 @@ export const OracleInfoPanel = ({
providers={data} providers={data}
type={type} type={type}
dataSourceSpecId={dataSourceSpecId} dataSourceSpecId={dataSourceSpecId}
parentData={
isParentDataSourceSpecEqual ? undefined : parentDataSourceSpec
}
parentDataSourceSpecId={
isParentDataSourceSpecIdEqual ? undefined : parentDataSourceSpecId
}
/> />
<ExternalLink <ExternalLink
data-testid="oracle-spec-links" data-testid="oracle-spec-links"
href={`${VEGA_EXPLORER_URL}/oracles/${ href={`${VEGA_EXPLORER_URL}/oracles/${
@ -606,14 +886,28 @@ export const DataSourceProof = ({
providers, providers,
type, type,
dataSourceSpecId, dataSourceSpecId,
parentData,
parentDataSourceSpecId,
}: { }: {
data: DataSourceDefinition; data: DataSourceDefinition;
providers: Provider[] | undefined; providers: Provider[] | undefined;
type: 'settlementData' | 'termination'; type: 'settlementData' | 'termination';
dataSourceSpecId: string; dataSourceSpecId: string;
parentData?: DataSourceDefinition;
parentDataSourceSpecId?: string;
}) => { }) => {
// If this is a successor market, we'll only pass parent data to child
// components for comparison if the data differs from the parent market.
if (data.sourceType.__typename === 'DataSourceDefinitionExternal') { if (data.sourceType.__typename === 'DataSourceDefinitionExternal') {
const signers = data.sourceType.sourceType.signers || []; const signers = data.sourceType.sourceType.signers || [];
let parentSigners: Signer[];
if (
parentData &&
parentData.sourceType.__typename === 'DataSourceDefinitionExternal'
) {
parentSigners = parentData.sourceType.sourceType?.signers || [];
}
if (!providers?.length) { if (!providers?.length) {
return <NoOracleProof type={type} />; return <NoOracleProof type={type} />;
@ -622,7 +916,14 @@ export const DataSourceProof = ({
return ( return (
<div className="flex flex-col gap-2"> <div className="flex flex-col gap-2">
{signers.map(({ signer }, i) => { {signers.map(({ signer }, i) => {
return ( const parentSigner = parentSigners?.find(
({ signer: ParentSigner }) =>
ParentSigner.__typename === signer.__typename
)?.signer;
const isParentSignerEqual = isEqual(signer, parentSigner);
return isParentSignerEqual ? (
<OracleLink <OracleLink
key={i} key={i}
providers={providers} providers={providers}
@ -630,6 +931,16 @@ export const DataSourceProof = ({
type={type} type={type}
dataSourceSpecId={dataSourceSpecId} dataSourceSpecId={dataSourceSpecId}
/> />
) : (
<OracleLink
key={i}
providers={providers}
signer={signer}
type={type}
dataSourceSpecId={dataSourceSpecId}
parentSigner={parentSigner}
parentDataSourceSpecId={parentDataSourceSpecId}
/>
); );
})} })}
</div> </div>
@ -663,18 +974,8 @@ export const DataSourceProof = ({
return <div>{t('Invalid data source')}</div>; return <div>{t('Invalid data source')}</div>;
}; };
const OracleLink = ({ const getSignerProviders = (signer: SignerKind, providers: Provider[]) =>
providers, providers.filter((p) => {
signer,
type,
dataSourceSpecId,
}: {
providers: Provider[];
signer: SignerKind;
type: 'settlementData' | 'termination';
dataSourceSpecId: string;
}) => {
const signerProviders = providers.filter((p) => {
if (signer.__typename === 'PubKey') { if (signer.__typename === 'PubKey') {
if ( if (
p.oracle.type === 'public_key' && p.oracle.type === 'public_key' &&
@ -696,19 +997,62 @@ const OracleLink = ({
return false; return false;
}); });
const OracleLink = ({
providers,
signer,
type,
dataSourceSpecId,
parentSigner,
parentDataSourceSpecId,
}: {
providers: Provider[];
signer: SignerKind;
type: 'settlementData' | 'termination';
dataSourceSpecId: string;
parentSigner?: SignerKind;
parentDataSourceSpecId?: string;
}) => {
// If this is a successor market, the parent market data will only have been passed
// in if it differs from the current data.
const signerProviders = getSignerProviders(signer, providers);
const parentSignerProviders = parentSigner
? getSignerProviders(parentSigner, providers)
: [];
if (!signerProviders.length) { if (!signerProviders.length) {
return <NoOracleProof type={type} />; return <NoOracleProof type={type} />;
} }
return ( return (
<div className="mt-2"> <div className="mt-2">
{signerProviders.map((provider) => ( {signerProviders.map((provider) => {
<OracleProfile // Making the assumption here that if the provider name is the same,
key={dataSourceSpecId} // that it is the same provider that the parent market used.
provider={provider} const parentProvider = parentSignerProviders.find(
dataSourceSpecId={dataSourceSpecId} (p) => p.name === provider.name
/> );
))}
const isParentProviderEqual =
parentProvider !== undefined && isEqual(provider, parentProvider);
// We only want to pass the parent data to the child component if the
// data differs from the parent market.
return isParentProviderEqual ? (
<OracleProfile
key={dataSourceSpecId}
provider={provider}
dataSourceSpecId={dataSourceSpecId}
/>
) : (
<OracleProfile
key={dataSourceSpecId}
provider={provider}
dataSourceSpecId={dataSourceSpecId}
parentProvider={parentProvider}
parentDataSourceSpecId={parentDataSourceSpecId}
/>
);
})}
</div> </div>
); );
}; };
@ -731,13 +1075,18 @@ const NoOracleProof = ({
const OracleProfile = (props: { const OracleProfile = (props: {
provider: Provider; provider: Provider;
dataSourceSpecId: string; dataSourceSpecId: string;
parentProvider?: Provider;
parentDataSourceSpecId?: string;
}) => { }) => {
// If this is a successor market, the parent market data will only have been passed
// in if it differs from the current data.
const [open, onChange] = useState(false); const [open, onChange] = useState(false);
return ( return (
<div key={props.provider.name}> <div key={props.provider.name}>
<OracleBasicProfile <OracleBasicProfile
provider={props.provider} provider={props.provider}
onClick={() => onChange(!open)} onClick={() => onChange(!open)}
parentProvider={props.parentProvider}
/> />
<OracleDialog {...props} open={open} onChange={onChange} /> <OracleDialog {...props} open={open} onChange={onChange} />
</div> </div>

View File

@ -5,6 +5,7 @@ import {
ExternalLink, ExternalLink,
Icon, Icon,
Intent, Intent,
Lozenge,
VegaIcon, VegaIcon,
VegaIconNames, VegaIconNames,
} from '@vegaprotocol/ui-toolkit'; } from '@vegaprotocol/ui-toolkit';
@ -59,10 +60,12 @@ export const OracleBasicProfile = ({
provider, provider,
onClick, onClick,
markets: oracleMarkets, markets: oracleMarkets,
parentProvider,
}: { }: {
provider: Provider; provider: Provider;
markets?: OracleMarketSpecFieldsFragment[] | undefined; markets?: OracleMarketSpecFieldsFragment[] | undefined;
onClick?: (value?: boolean) => void; onClick?: (value?: boolean) => void;
parentProvider?: Provider;
}) => { }) => {
const { icon, message, intent } = getVerifiedStatusIcon(provider); const { icon, message, intent } = getVerifiedStatusIcon(provider);
@ -78,8 +81,14 @@ export const OracleBasicProfile = ({
icon: getLinkIcon(proof.type), icon: getLinkIcon(proof.type),
})); }));
// If this is a successor market and there's a different parent provider,
// we'll just show that there's been a change, rather than add old data
// in alongside the new provider.
return ( return (
<> <>
{parentProvider && (
<Lozenge variant={Intent.Primary}>{t('Updated')}</Lozenge>
)}
<span className="flex gap-1"> <span className="flex gap-1">
{provider.url && ( {provider.url && (
<span className="flex align-items-bottom text-md gap-1"> <span className="flex align-items-bottom text-md gap-1">

View File

@ -11,16 +11,27 @@ export const OracleDialog = ({
dataSourceSpecId, dataSourceSpecId,
open, open,
onChange, onChange,
parentProvider,
}: { }: {
dataSourceSpecId: string; dataSourceSpecId: string;
provider: Provider; provider: Provider;
open: boolean; open: boolean;
onChange?: (isOpen: boolean) => void; onChange?: (isOpen: boolean) => void;
parentProvider?: Provider;
}) => { }) => {
// If this is a successor market, the parent market data will only have been passed
// in if it differs from the current data. We'll pass this on to the title component
// to show a change, but the full profile showing changes is unwieldy - it's enough
// to know from the title that the oracle has changed.
const oracleMarkets = useOracleMarkets(provider); const oracleMarkets = useOracleMarkets(provider);
return ( return (
<Dialog <Dialog
title={<OracleProfileTitle provider={provider} />} title={
<OracleProfileTitle
provider={provider}
parentProvider={parentProvider}
/>
}
aria-labelledby="oracle-proof-dialog" aria-labelledby="oracle-proof-dialog"
open={open} open={open}
onChange={onChange} onChange={onChange}

View File

@ -6,6 +6,7 @@ import {
ExternalLink, ExternalLink,
Icon, Icon,
Intent, Intent,
Lozenge,
VegaIcon, VegaIcon,
VegaIconNames, VegaIconNames,
} from '@vegaprotocol/ui-toolkit'; } from '@vegaprotocol/ui-toolkit';
@ -18,15 +19,30 @@ import type { OracleMarketSpecFieldsFragment } from '../../__generated__/OracleM
import ReactMarkdown from 'react-markdown'; import ReactMarkdown from 'react-markdown';
import { useState } from 'react'; import { useState } from 'react';
export const OracleProfileTitle = ({ provider }: { provider: Provider }) => { export const OracleProfileTitle = ({
provider,
parentProvider,
}: {
provider: Provider;
parentProvider?: Provider;
}) => {
// If this is a successor market, the parent provider will only have been passed
// in if it differs from the current provider. If it is different, we'll just
// show the change in name, not icons and proofs.
const { icon, intent } = getVerifiedStatusIcon(provider); const { icon, intent } = getVerifiedStatusIcon(provider);
const verifiedProofs = provider.proofs.filter( const verifiedProofs = provider.proofs.filter(
(proof) => proof.available === true (proof) => proof.available === true
); );
return ( return (
<span className="flex gap-1"> <span className="flex gap-1">
{parentProvider && (
<Lozenge variant={Intent.Primary}>{t('Updated')}</Lozenge>
)}
{provider.url && ( {provider.url && (
<span> <span>
{parentProvider && parentProvider.name && (
<span className="line-through">{parentProvider.name}</span>
)}
<span className="pr-1">{provider.name}</span> <span className="pr-1">{provider.name}</span>
<span className="dark:text-vega-light-300 text-vega-dark-300"> <span className="dark:text-vega-light-300 text-vega-dark-300">
({verifiedProofs.length}) ({verifiedProofs.length})

View File

@ -22,7 +22,7 @@ export const getIntentBackground = (intent?: Intent) => {
return { return {
'bg-neutral-200 dark:bg-neutral-800': intent === undefined, 'bg-neutral-200 dark:bg-neutral-800': intent === undefined,
'bg-black dark:bg-white': intent === Intent.None, 'bg-black dark:bg-white': intent === Intent.None,
'bg-vega-blue-300 dark:bg-vega-blue-700': intent === Intent.Primary, 'bg-vega-blue-300 dark:bg-vega-blue-650': intent === Intent.Primary,
'bg-danger': intent === Intent.Danger, 'bg-danger': intent === Intent.Danger,
'bg-warning': intent === Intent.Warning, 'bg-warning': intent === Intent.Warning,
// contrast issues with light mode // contrast issues with light mode