Merge pull request #371 from FinnCastro/finn/dashboard-ui-improvements

UI Readability Improvements For Dashboard
This commit is contained in:
saml33 2024-01-22 23:45:13 +11:00 committed by GitHub
commit 95197fbe69
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 1402 additions and 1392 deletions

View File

@ -16,6 +16,7 @@ interface SelectProps<T extends Values> {
icon?: ReactNode
placeholder?: string
disabled?: boolean
renderValue?: (value: T | string) => ReactNode
}
const Select = <T extends Values>({
@ -28,6 +29,7 @@ const Select = <T extends Values>({
icon,
placeholder = 'Select',
disabled = false,
renderValue,
}: SelectProps<T>) => {
return (
<div className={`relative ${className}`}>
@ -43,7 +45,11 @@ const Select = <T extends Values>({
<div className="flex items-center">
{icon ? icon : null}
{value ? (
value
renderValue ? (
renderValue(value)
) : (
value
)
) : (
<span className="text-th-fgd-3">{placeholder}</span>
)}

View File

@ -16,23 +16,32 @@ export const Table = ({
export const TrHead = ({
children,
className,
style,
}: {
children: ReactNode
className?: string
}) => <tr className={`border-b border-th-bkg-3 ${className}`}>{children}</tr>
style?: object
}) => (
<tr style={style} className={`border-b border-th-bkg-3 ${className}`}>
{children}
</tr>
)
export const Th = ({
style,
children,
className,
id,
xBorder = false,
}: {
style?: object
children?: ReactNode
className?: string
id?: string
xBorder?: boolean
}) => (
<th
style={style}
className={`whitespace-nowrap px-2 py-3 text-xs font-normal text-th-fgd-3 first:pl-6 last:pr-6 xl:px-4 ${
xBorder ? 'border-x border-th-bkg-3' : ''
} ${className}`}

File diff suppressed because it is too large Load Diff

View File

@ -70,363 +70,324 @@ const MangoAccountDashboard: NextPage = () => {
}, [mangoAccount, loadOpenOrders])
return (
<div className="grid grid-cols-12">
<div className="col-span-12 lg:col-span-8 lg:col-start-3">
<div className="p-8 pb-20 md:pb-16 lg:p-10">
<h1>Dashboard</h1>
<DashboardNavbar />
<div className="">
<div className="mt-4 flex space-x-2">
<Input
type="text"
name="search"
id="search"
value={searchString}
onChange={(e: ChangeEvent<HTMLInputElement>) =>
setSearchString(e.target.value)
}
/>
<Button
className="flex items-center"
onClick={() => {
const encodedSearchString = encodeURIComponent(searchString)
router.push(
`/dashboard/mangoaccount?address=${encodedSearchString}`,
)
}}
disabled={!searchString}
size="large"
>
<MagnifyingGlassIcon className="mr-2 h-5 w-5" />
Search
</Button>
</div>
</div>
{group && mangoAccount ? (
<div className="mt-4">
<h2 className="mb-6">Mango Account</h2>
<div className="col-span-12 lg:col-span-8 lg:col-start-3">
<DashboardNavbar />
<div className="ml-80 mr-80">
<div className="mt-4 flex space-x-2">
<Input
type="text"
name="search"
id="search"
value={searchString}
onChange={(e: ChangeEvent<HTMLInputElement>) =>
setSearchString(e.target.value)
}
/>
<Button
className="flex items-center"
onClick={() => {
const encodedSearchString = encodeURIComponent(searchString)
router.push(
`/dashboard/mangoaccount?address=${encodedSearchString}`,
)
}}
disabled={!searchString}
size="large"
>
<MagnifyingGlassIcon className="mr-2 h-5 w-5" />
Search
</Button>
</div>
</div>
{group && mangoAccount ? (
<div className="ml-80 mr-80 mt-4">
<h2 className="mb-6">Mango Account</h2>
<KeyValuePair
label="Address"
value={
<ExplorerLink address={mangoAccount.publicKey.toString()} />
}
/>
<KeyValuePair
label="Owner"
value={<ExplorerLink address={mangoAccount.owner.toString()} />}
/>
<KeyValuePair label="Name" value={mangoAccount.name.toString()} />
<KeyValuePair
label="Delegate"
value={
<ExplorerLink address={mangoAccount.delegate.toString()} />
}
/>
<KeyValuePair
label="Account Number"
value={mangoAccount.accountNum.toString()}
/>
<KeyValuePair
label="Being Liquidated"
value={mangoAccount.beingLiquidated.toString()}
/>
<KeyValuePair
label="Init Health"
value={`$${toUiDecimalsForQuote(
mangoAccount.getHealth(group, HealthType.init),
).toFixed(4)}`}
/>
<KeyValuePair
label="Maint Health"
value={`$${toUiDecimalsForQuote(
mangoAccount.getHealth(group, HealthType.maint),
).toFixed(4)}`}
/>
{/* <KeyValuePair
<KeyValuePair
label="Address"
value={<ExplorerLink address={mangoAccount.publicKey.toString()} />}
/>
<KeyValuePair
label="Owner"
value={<ExplorerLink address={mangoAccount.owner.toString()} />}
/>
<KeyValuePair label="Name" value={mangoAccount.name.toString()} />
<KeyValuePair
label="Delegate"
value={<ExplorerLink address={mangoAccount.delegate.toString()} />}
/>
<KeyValuePair
label="Account Number"
value={mangoAccount.accountNum.toString()}
/>
<KeyValuePair
label="Being Liquidated"
value={mangoAccount.beingLiquidated.toString()}
/>
<KeyValuePair
label="Init Health"
value={`$${toUiDecimalsForQuote(
mangoAccount.getHealth(group, HealthType.init),
).toFixed(4)}`}
/>
<KeyValuePair
label="Maint Health"
value={`$${toUiDecimalsForQuote(
mangoAccount.getHealth(group, HealthType.maint),
).toFixed(4)}`}
/>
{/* <KeyValuePair
label="Perp Settle Health"
value={`$${toUiDecimalsForQuote(
mangoAccount.getPerpSettleHealth(group)
).toFixed(4)}`}
/> */}
<KeyValuePair
label="Net Deposits"
value={`$${toUiDecimalsForQuote(
mangoAccount.netDeposits,
).toFixed(4)}`}
/>
<KeyValuePair
label="Perp Spot Transfers"
value={mangoAccount.perpSpotTransfers.toNumber()}
/>
<KeyValuePair
label="Health Region Begin Init Health"
value={mangoAccount.healthRegionBeginInitHealth.toNumber()}
/>
<KeyValuePair
label="Perp OO Count"
value={mangoAccount.perpOpenOrders.length}
/>
<KeyValuePair
label="Perp Active OO Count"
value={mangoAccount.perpOrdersActive().length}
/>
<KeyValuePair
label="Perp Position Count"
value={mangoAccount.perps.length}
/>
<KeyValuePair
label="Active Perp Position Count"
value={mangoAccount.perpActive().length}
/>
<KeyValuePair
label="Token Position Count"
value={mangoAccount.tokens.length}
/>
<KeyValuePair
label="Active Token Position Count"
value={mangoAccount.tokensActive().length}
/>
<KeyValuePair
label="Serum OO Count"
value={mangoAccount.serum3.length}
/>
<KeyValuePair
label="Active Serum OO Count"
value={mangoAccount.serum3Active().length}
/>
<KeyValuePair
label="Net Deposits"
value={`$${toUiDecimalsForQuote(mangoAccount.netDeposits).toFixed(
4,
)}`}
/>
<KeyValuePair
label="Perp Spot Transfers"
value={mangoAccount.perpSpotTransfers.toNumber()}
/>
<KeyValuePair
label="Health Region Begin Init Health"
value={mangoAccount.healthRegionBeginInitHealth.toNumber()}
/>
<KeyValuePair
label="Perp OO Count"
value={mangoAccount.perpOpenOrders.length}
/>
<KeyValuePair
label="Perp Active OO Count"
value={mangoAccount.perpOrdersActive().length}
/>
<KeyValuePair
label="Perp Position Count"
value={mangoAccount.perps.length}
/>
<KeyValuePair
label="Active Perp Position Count"
value={mangoAccount.perpActive().length}
/>
<KeyValuePair
label="Token Position Count"
value={mangoAccount.tokens.length}
/>
<KeyValuePair
label="Active Token Position Count"
value={mangoAccount.tokensActive().length}
/>
<KeyValuePair
label="Serum OO Count"
value={mangoAccount.serum3.length}
/>
<KeyValuePair
label="Active Serum OO Count"
value={mangoAccount.serum3Active().length}
/>
<h3 className="mt-4">Token Active Positions</h3>
{mangoAccount.tokensActive().map((token) => {
const bank = group.getFirstBankByTokenIndex(token.tokenIndex)
<h3 className="mt-4">Token Active Positions</h3>
{mangoAccount.tokensActive().map((token) => {
const bank = group.getFirstBankByTokenIndex(token.tokenIndex)
return (
<div key={token.tokenIndex} className="mt-6">
<KeyValuePair label="Token's Bank Name" value={bank.name} />
<KeyValuePair
label="Deposits Native"
value={token.deposits(bank).toString()}
/>
<KeyValuePair
label="Borrow Native"
value={token.borrows(bank).toString()}
/>
<KeyValuePair
label="Balance UI"
value={token.balanceUi(bank)}
/>
<KeyValuePair
label="Value at oracle price"
value={`$${token.balanceUi(bank) * bank.uiPrice}`}
/>
<KeyValuePair
label="In Use Count"
value={`${token.inUseCount}`}
/>
</div>
)
})}
<h3 className="mt-4">Serum3 Active Positions</h3>
{mangoAccount.serum3Active().map((serum) => {
const market = group.getSerum3MarketByMarketIndex(serum.marketIndex)
const extMarket = group.getSerum3ExternalMarket(
market.serumMarketExternal,
)
return (
<div key={serum.marketIndex} className="mt-6">
<KeyValuePair
label="Serum Market"
value={<ExplorerLink address={market.publicKey.toString()} />}
/>
<KeyValuePair
label="Serum External Market"
value={
<ExplorerLink address={extMarket.publicKey.toString()} />
}
/>
<KeyValuePair label="Name" value={market.name} />
<KeyValuePair label="Market Index" value={serum.marketIndex} />
<KeyValuePair
label="Open Orders"
value={serum.openOrders.toBase58()}
/>
</div>
)
})}
<h3 className="mt-4">Perp Active Positions</h3>
{mangoAccount.perpActive().map((perp) => {
const market = group.getPerpMarketByMarketIndex(perp.marketIndex)
return (
<div key={perp.marketIndex} className="mt-6">
<KeyValuePair
label="Market"
value={<ExplorerLink address={market.publicKey.toString()} />}
/>
<KeyValuePair label="Market Index" value={perp.marketIndex} />
<KeyValuePair label="Name" value={market.name} />
<KeyValuePair
label="Base Position Lots"
value={perp.basePositionLots.toNumber()}
/>
<KeyValuePair
label="Base Position Ui"
value={perp.getBasePositionUi(market)}
/>
<KeyValuePair
label="Quote Position"
value={`$${toUiDecimalsForQuote(
perp.quotePositionNative,
).toFixed(4)}`}
/>
<KeyValuePair
label="Equity"
value={`$${perp.getEquityUi(market).toFixed(6)}`}
/>
<KeyValuePair
label="Unsettled Funding"
value={`$${toUiDecimalsForQuote(
perp.getUnsettledFunding(market),
).toFixed(6)}`}
/>
<KeyValuePair
label="Avg Entry Price"
value={`$${perp.getAverageEntryPriceUi(market).toFixed(6)}`}
/>
<KeyValuePair
label="Break even price"
value={`$${perp.getBreakEvenPriceUi(market).toFixed(6)}`}
/>
<KeyValuePair
label="Max Settle"
value={`$${toUiDecimalsForQuote(
mangoAccount.perpMaxSettle(group, market.settleTokenIndex),
).toFixed(6)}`}
/>
<KeyValuePair
label="Quote Running"
value={`$${toUiDecimalsForQuote(
perp.quoteRunningNative,
).toFixed(6)}`}
/>
<KeyValuePair
label="Cumulative Funding"
value={`$${toUiDecimalsForQuote(
-perp.cumulativeLongFunding,
).toFixed(6)} long / $${toUiDecimalsForQuote(
perp.cumulativeShortFunding,
).toFixed(6)} short / $${toUiDecimalsForQuote(
-perp.cumulativeLongFunding + perp.cumulativeShortFunding,
).toFixed(6)} total`}
/>
<KeyValuePair
label="Taker Lots"
value={`${perp.takerQuoteLots.toNumber()} quote / ${perp.takerBaseLots.toNumber()} base`}
/>
<KeyValuePair
label="Open Orders Lots"
value={`${perp.bidsBaseLots.toNumber()} bids / ${perp.asksBaseLots.toNumber()} asks`}
/>
<KeyValuePair
label="Has open orders"
value={perp.hasOpenOrders().toString()}
/>
<KeyValuePair
label="Volume"
value={`$${toUiDecimalsForQuote(perp.makerVolume).toFixed(
6,
)} maker / $${toUiDecimalsForQuote(perp.takerVolume).toFixed(
6,
)} taker`}
/>
<KeyValuePair
label="Perp-Spot Transfers"
value={`$${toUiDecimalsForQuote(
perp.perpSpotTransfers,
).toFixed(6)}`}
/>
<KeyValuePair
label="Position Lifetime PnL"
value={`$${toUiDecimalsForQuote(
perp.realizedPnlForPositionNative,
).toFixed(6)} realized / $${toUiDecimalsForQuote(
perp.cumulativePnlOverPositionLifetimeUi(market),
).toFixed(6)} total`}
/>
</div>
)
})}
<h3 className="mt-4">Perp Open Orders</h3>
{openOrders
? Object.entries(openOrders).map(([marketAddress, openOrders]) => {
return (
<div key={token.tokenIndex} className="mt-6">
<KeyValuePair label="Token's Bank Name" value={bank.name} />
<div key={marketAddress} className="mt-4">
<KeyValuePair
label="Deposits Native"
value={token.deposits(bank).toString()}
label="Market Address"
value={<ExplorerLink address={marketAddress} />}
/>
<KeyValuePair
label="Borrow Native"
value={token.borrows(bank).toString()}
/>
<KeyValuePair
label="Balance UI"
value={token.balanceUi(bank)}
/>
<KeyValuePair
label="Value at oracle price"
value={`$${token.balanceUi(bank) * bank.uiPrice}`}
/>
<KeyValuePair
label="In Use Count"
value={`${token.inUseCount}`}
/>
</div>
)
})}
<h3 className="mt-4">Serum3 Active Positions</h3>
{mangoAccount.serum3Active().map((serum) => {
const market = group.getSerum3MarketByMarketIndex(
serum.marketIndex,
)
const extMarket = group.getSerum3ExternalMarket(
market.serumMarketExternal,
)
return (
<div key={serum.marketIndex} className="mt-6">
<KeyValuePair
label="Serum Market"
value={
<ExplorerLink address={market.publicKey.toString()} />
}
/>
<KeyValuePair
label="Serum External Market"
value={
<ExplorerLink
address={extMarket.publicKey.toString()}
/>
}
/>
<KeyValuePair label="Name" value={market.name} />
<KeyValuePair
label="Market Index"
value={serum.marketIndex}
/>
<KeyValuePair
label="Open Orders"
value={serum.openOrders.toBase58()}
/>
</div>
)
})}
<h3 className="mt-4">Perp Active Positions</h3>
{mangoAccount.perpActive().map((perp) => {
const market = group.getPerpMarketByMarketIndex(
perp.marketIndex,
)
return (
<div key={perp.marketIndex} className="mt-6">
<KeyValuePair
label="Market"
value={
<ExplorerLink address={market.publicKey.toString()} />
}
/>
<KeyValuePair
label="Market Index"
value={perp.marketIndex}
/>
<KeyValuePair label="Name" value={market.name} />
<KeyValuePair
label="Base Position Lots"
value={perp.basePositionLots.toNumber()}
/>
<KeyValuePair
label="Base Position Ui"
value={perp.getBasePositionUi(market)}
/>
<KeyValuePair
label="Quote Position"
value={`$${toUiDecimalsForQuote(
perp.quotePositionNative,
).toFixed(4)}`}
/>
<KeyValuePair
label="Equity"
value={`$${perp.getEquityUi(market).toFixed(6)}`}
/>
<KeyValuePair
label="Unsettled Funding"
value={`$${toUiDecimalsForQuote(
perp.getUnsettledFunding(market),
).toFixed(6)}`}
/>
<KeyValuePair
label="Avg Entry Price"
value={`$${perp
.getAverageEntryPriceUi(market)
.toFixed(6)}`}
/>
<KeyValuePair
label="Break even price"
value={`$${perp.getBreakEvenPriceUi(market).toFixed(6)}`}
/>
<KeyValuePair
label="Max Settle"
value={`$${toUiDecimalsForQuote(
mangoAccount.perpMaxSettle(
group,
market.settleTokenIndex,
),
).toFixed(6)}`}
/>
<KeyValuePair
label="Quote Running"
value={`$${toUiDecimalsForQuote(
perp.quoteRunningNative,
).toFixed(6)}`}
/>
<KeyValuePair
label="Cumulative Funding"
value={`$${toUiDecimalsForQuote(
-perp.cumulativeLongFunding,
).toFixed(6)} long / $${toUiDecimalsForQuote(
perp.cumulativeShortFunding,
).toFixed(6)} short / $${toUiDecimalsForQuote(
-perp.cumulativeLongFunding +
perp.cumulativeShortFunding,
).toFixed(6)} total`}
/>
<KeyValuePair
label="Taker Lots"
value={`${perp.takerQuoteLots.toNumber()} quote / ${perp.takerBaseLots.toNumber()} base`}
/>
<KeyValuePair
label="Open Orders Lots"
value={`${perp.bidsBaseLots.toNumber()} bids / ${perp.asksBaseLots.toNumber()} asks`}
/>
<KeyValuePair
label="Has open orders"
value={perp.hasOpenOrders().toString()}
/>
<KeyValuePair
label="Volume"
value={`$${toUiDecimalsForQuote(perp.makerVolume).toFixed(
6,
)} maker / $${toUiDecimalsForQuote(
perp.takerVolume,
).toFixed(6)} taker`}
/>
<KeyValuePair
label="Perp-Spot Transfers"
value={`$${toUiDecimalsForQuote(
perp.perpSpotTransfers,
).toFixed(6)}`}
/>
<KeyValuePair
label="Position Lifetime PnL"
value={`$${toUiDecimalsForQuote(
perp.realizedPnlForPositionNative,
).toFixed(6)} realized / $${toUiDecimalsForQuote(
perp.cumulativePnlOverPositionLifetimeUi(market),
).toFixed(6)} total`}
/>
</div>
)
})}
<h3 className="mt-4">Perp Open Orders</h3>
{openOrders
? Object.entries(openOrders).map(
([marketAddress, openOrders]) => {
{openOrders.map((openOrder) => {
return (
<div key={marketAddress} className="mt-4">
<div
key={`${openOrder.orderId}${openOrder.side}${openOrder.seqNum}`}
className="mt-4 rounded border border-th-bkg-3 px-2"
>
<KeyValuePair
label="Market Address"
value={<ExplorerLink address={marketAddress} />}
label="Side"
value={
openOrder.side
? 'bid' in openOrder.side
? 'Bid'
: 'Ask'
: null
}
/>
{openOrders.map((openOrder) => {
return (
<div
key={`${openOrder.orderId}${openOrder.side}${openOrder.seqNum}`}
className="mt-4 rounded border border-th-bkg-3 px-2"
>
<KeyValuePair
label="Side"
value={
openOrder.side
? 'bid' in openOrder.side
? 'Bid'
: 'Ask'
: null
}
/>
<KeyValuePair
label="Price"
value={openOrder.price}
/>
<KeyValuePair
label="Size"
value={openOrder.size}
/>
</div>
)
})}
<KeyValuePair label="Price" value={openOrder.price} />
<KeyValuePair label="Size" value={openOrder.size} />
</div>
)
},
)
: null}
</div>
) : (
<div className="m-4 flex items-center">Loading account data...</div>
)}
})}
</div>
)
})
: null}
</div>
</div>
) : (
<div className="m-4 flex items-center">Loading account data...</div>
)}
</div>
)
}
@ -439,7 +400,7 @@ const KeyValuePair = ({
value: number | ReactNode | string
}) => {
return (
<div className="flex justify-between border-t border-th-bkg-3 py-4 xl:py-1.5">
<div className="flex justify-between border-t border-th-bkg-3 py-4 md:hover:bg-th-bkg-2 xl:py-1.5">
<span className="mr-4 whitespace-nowrap text-th-fgd-3">{label}</span>
{value}
</div>

View File

@ -81,90 +81,77 @@ const RiskDashboard: NextPage = () => {
)
return (
<div className="grid grid-cols-12">
<div className="col-span-12 lg:col-span-8 lg:col-start-3">
<div className="p-8 pb-20 md:pb-16 lg:p-10">
<h1>Dashboard</h1>
{data?.timestamp ? <h6> As of: {data.timestamp} UTC </h6> : null}
<DashboardNavbar />
{group && data && data.payload ? (
<div className="mt-4">
{Object.entries(data.payload).map(
([tableType, table]: [string, TableData]) => {
if (!table?.data?.length) return null
return (
<div className="mt-12" key={tableType}>
<div className="mb-4">
<p className="text-th-fgd-4">{table.title}</p>
</div>
<Table>
<thead>
<TrHead className="border">
{Object.keys(table.data[0]).map(
(colName: string) => {
return (
<Th
xBorder
className="text-left"
key={colName}
>
{colName}{' '}
{colName.toLowerCase().includes('fee') ||
colName.toLowerCase().includes('slippage')
? '(bps)'
: ''}
{colName.toLowerCase().includes('assets') ||
colName.toLowerCase().includes('liabs') ||
colName.toLowerCase().includes('equity') ||
colName.toLowerCase().includes('price') ||
colName.toLowerCase().includes('position')
? '($)'
: ''}
</Th>
)
},
)}
</TrHead>
</thead>
<tbody>
{table.data.map((rowData, index: number) => {
return (
<TrBody
className={index % 2 === 0 ? 'bg-th-bkg-2' : ''}
key={index}
>
{Object.values(rowData).map(
(val, idx: number) => {
return (
<Td
xBorder
className={`${
val?.highlight ? 'bg-th-bkg-4' : ''
}`}
key={idx}
>
{formatValue(val?.val)}
</Td>
)
},
)}
</TrBody>
)
})}
</tbody>
</Table>
</div>
)
},
)}
</div>
) : (
<div className="mt-8 w-full text-center">
Loading... make take up to 60 seconds
</div>
<div className="col-span-12 lg:col-span-8 lg:col-start-3">
<DashboardNavbar />
{data?.timestamp ? <h6> As of: {data.timestamp} UTC </h6> : null}
{group && data && data.payload ? (
<div className="mt-4">
{Object.entries(data.payload).map(
([tableType, table]: [string, TableData]) => {
if (!table?.data?.length) return null
return (
<div className="mt-12" key={tableType}>
<div className="mb-4">
<p className="text-th-fgd-4">{table.title}</p>
</div>
<Table>
<thead>
<TrHead className="border">
{Object.keys(table.data[0]).map((colName: string) => {
return (
<Th xBorder className="text-left" key={colName}>
{colName}{' '}
{colName.toLowerCase().includes('fee') ||
colName.toLowerCase().includes('slippage')
? '(bps)'
: ''}
{colName.toLowerCase().includes('assets') ||
colName.toLowerCase().includes('liabs') ||
colName.toLowerCase().includes('equity') ||
colName.toLowerCase().includes('price') ||
colName.toLowerCase().includes('position')
? '($)'
: ''}
</Th>
)
})}
</TrHead>
</thead>
<tbody>
{table.data.map((rowData, index: number) => {
return (
<TrBody
className={index % 2 === 0 ? 'bg-th-bkg-2 ' : ''}
key={index}
>
{Object.values(rowData).map((val, idx: number) => {
return (
<Td
xBorder
className={`${
val?.highlight ? 'bg-th-bkg-4' : ''
}`}
key={idx}
>
{formatValue(val?.val)}
</Td>
)
})}
</TrBody>
)
})}
</tbody>
</Table>
</div>
)
},
)}
</div>
</div>
) : (
<div className="mt-8 w-full text-center">
Loading... make take up to 60 seconds
</div>
)}
</div>
)
}

View File

@ -57,8 +57,12 @@ const RiskDashboard: NextPage = () => {
'avg_price_impact' | 'p90' | 'p95'
>('avg_price_impact')
const [currentSearch, setCurrentSearch] = useState('')
const filters = ['avg_price_impact', 'p90', 'p95']
const filterLabels = {
avg_price_impact: 'Average Price Impact',
p90: '90th Percentile',
p95: '95th Percentile',
}
const heads = group
? [
@ -151,216 +155,288 @@ const RiskDashboard: NextPage = () => {
)
return (
<div className="grid grid-cols-12">
<div className="col-span-12 lg:col-span-8 lg:col-start-3">
<div className="p-8 pb-20 md:pb-16 lg:p-10">
<h1>Dashboard</h1>
<DashboardNavbar />
{group ? (
<div className="mt-4">
<div className="mt-12">
<div className="mb-4">
<p className="flex items-center space-x-4 text-th-fgd-4">
<span>Slippage</span>
<Select
value={currentFilter}
onChange={(filter) => setCurrentFilter(filter)}
className="w-full"
<div className="col-span-12 w-full lg:col-span-8 lg:col-start-3">
<DashboardNavbar />
{group ? (
<div className="mt-4">
<div className="mb-4 ml-20 mr-20">
<p className="flex items-center space-x-4 text-th-fgd-4">
<span>Slippage</span>
<Select
value={currentFilter}
onChange={(filter) => setCurrentFilter(filter)}
className="w-full"
renderValue={(selected) =>
filterLabels[selected as keyof typeof filterLabels]
}
>
{filters.map((filter) => {
return (
<Select.Option key={filter} value={filter}>
<div className="flex w-full items-center justify-between">
{filterLabels[filter as keyof typeof filterLabels]}
</div>
</Select.Option>
)
})}
</Select>
<Input
suffix="Token"
type="text"
heightClass={'h-10'}
value={currentSearch}
onChange={(e) => setCurrentSearch(e.target.value)}
></Input>
</p>
</div>
<div className="w-full overflow-scroll" style={{ maxHeight: '70vh' }}>
<Table className="h-full">
<thead>
<TrHead
style={{ boxShadow: '1px -5px 1px #1d1924', zIndex: 19 }}
className="sticky top-0 border-t bg-th-bkg-2"
>
{heads.map((x, i: number) => (
<Th key={x} xBorder={i != 0} className={`text-left`}>
{x}
</Th>
))}
</TrHead>
</thead>
<tbody>
{transformedPis?.map((row, idx: number) => {
const banks = group?.banksMapByName?.get(
apiNameToBankName(row.symbol),
)
const bank = banks && banks[0]
const borrowsEnabled = bank?.reduceOnly === 0
const hasAssetWeight =
bank &&
(bank.initAssetWeight.toNumber() > 0 ||
bank.maintAssetWeight.toNumber() > 0)
const isBid = row.side === 'bid'
const isAsk = row.side === 'ask'
const collateralEnabled = bank?.maintAssetWeight.isPos()
return (
<TrBody
key={idx}
className="h-10 text-xs md:hover:bg-th-bkg-2"
>
{filters.map((filter) => (
<Select.Option key={filter} value={filter}>
<div className="flex w-full items-center justify-between">
{filter}
</div>
</Select.Option>
))}
</Select>
<Input
suffix="Token"
type="text"
value={currentSearch}
onChange={(e) => setCurrentSearch(e.target.value)}
></Input>
</p>
</div>
<Table>
<thead>
<TrHead className="sticky top-0 border bg-th-bkg-1">
{heads.map((x) => (
<Th key={x} xBorder className="text-left">
{x}
</Th>
))}
</TrHead>
</thead>
<tbody>
{transformedPis?.map((row, idx: number) => {
const banks = group?.banksMapByName?.get(
apiNameToBankName(row.symbol),
)
const bank = banks && banks[0]
{Object.entries(row).map(([key, val], valIdx) => {
const visibleValue =
typeof val === 'string' ? val : val[currentFilter]
const isNumericValue = typeof visibleValue === 'number'
const targetAmount =
(key.includes('amount_') &&
Number(key.replace('amount_', ''))) ||
0
const uiBorrowWeightScaleStartQuote =
bank &&
toUiDecimals(bank.borrowWeightScaleStartQuote, 6)
const uiDepositWeightScaleStartQuote =
bank &&
toUiDecimals(bank.depositWeightScaleStartQuote, 6)
const notionalDeposits =
(bank && bank!.uiDeposits() * bank!.uiPrice) || 0
const notionalBorrows =
(bank && bank!.uiBorrows() * bank!.uiPrice) || 0
const borrowsEnabled = bank?.reduceOnly === 0
const hasAssetWeight =
bank &&
(bank.initAssetWeight.toNumber() > 0 ||
bank.maintAssetWeight.toNumber() > 0)
const isBid = row.side === 'bid'
const isAsk = row.side === 'ask'
const collateralEnabled = bank?.maintAssetWeight.isPos()
return (
<TrBody key={idx}>
{Object.entries(row).map(([key, val], valIdx) => {
const visibleValue =
typeof val === 'string' ? val : val[currentFilter]
const isNumericValue =
typeof visibleValue === 'number'
const targetAmount =
(key.includes('amount_') &&
Number(key.replace('amount_', ''))) ||
0
const uiBorrowWeightScaleStartQuote =
bank &&
toUiDecimals(bank.borrowWeightScaleStartQuote, 6)
const uiDepositWeightScaleStartQuote =
bank &&
toUiDecimals(bank.depositWeightScaleStartQuote, 6)
const notionalDeposits =
(bank && bank!.uiDeposits() * bank!.uiPrice) || 0
const notionalBorrows =
(bank && bank!.uiBorrows() * bank!.uiPrice) || 0
const isAboveLiqFee =
(hasAssetWeight || borrowsEnabled) &&
isNumericValue &&
visibleValue > bank.liquidationFee.toNumber() * 100
const isAboveLiqFee =
(hasAssetWeight || borrowsEnabled) &&
isNumericValue &&
visibleValue >
bank.liquidationFee.toNumber() * 100
const targetAmountVsDeposits =
isBid && targetAmount <= notionalDeposits
const targetAmountVsBorrows =
isAsk && targetAmount <= notionalBorrows
const targetAmountVsDeposits =
isBid && targetAmount <= notionalDeposits
const targetAmountVsBorrows =
isAsk && targetAmount <= notionalBorrows
const targetAmountVsAssetWeightScale =
isBid &&
collateralEnabled &&
uiBorrowWeightScaleStartQuote &&
targetAmount <= uiBorrowWeightScaleStartQuote
const targetAmountVsAssetWeightScale =
isBid &&
collateralEnabled &&
uiBorrowWeightScaleStartQuote &&
targetAmount <= uiBorrowWeightScaleStartQuote
const targetAmountVsLiabWeightScale =
isAsk &&
collateralEnabled &&
uiDepositWeightScaleStartQuote &&
targetAmount <= uiDepositWeightScaleStartQuote
const targetAmountVsLiabWeightScale =
isAsk &&
collateralEnabled &&
uiDepositWeightScaleStartQuote &&
targetAmount <= uiDepositWeightScaleStartQuote
return (
<Td
xBorder
key={valIdx}
className={`!p-1 ${
isAboveLiqFee ? 'text-th-error' : ''
}`}
>
<div className="flex">
<div className="mr-2 h-full">
{formatValue(visibleValue)}
</div>
{isNumericValue && (
<div className="ml-auto flex w-4">
{(targetAmountVsBorrows ||
targetAmountVsDeposits) && (
<div className="w-2 bg-[#ffff99]"></div>
)}
{(targetAmountVsAssetWeightScale ||
targetAmountVsLiabWeightScale) && (
<div className="w-2 bg-[#0066ff]"></div>
)}
</div>
return (
<Td
xBorder={valIdx != 0}
key={valIdx}
className={`!py-3
${valIdx == 0 ? 'z-1 sticky left-0 bg-th-bkg-2' : ''}
${isAboveLiqFee ? 'text-th-error' : ''}`}
>
<div className="flex">
<div className="mr-2 h-full">
{formatValue(visibleValue)}
</div>
{isNumericValue && (
<div className="ml-auto flex w-4">
{(targetAmountVsBorrows ||
targetAmountVsDeposits) && (
<div className="w-2 bg-[#ffff99]"></div>
)}
{(targetAmountVsAssetWeightScale ||
targetAmountVsLiabWeightScale) && (
<div className="w-2 bg-[#0066ff]"></div>
)}
</div>
</Td>
)}
</div>
</Td>
)
})}
<Td xBorder>
{isBid &&
collateralEnabled &&
`${
bank &&
formatValue(
bank
?.scaledInitAssetWeight(bank.price)
.toNumber(),
)
})}
<Td xBorder>
{isBid &&
collateralEnabled &&
`${
bank &&
formatValue(
bank
?.scaledInitAssetWeight(bank.price)
.toNumber(),
)
} / ${
bank &&
formatValue(bank.maintAssetWeight.toNumber())
}`}
} / ${
bank &&
formatValue(bank.maintAssetWeight.toNumber())
}`}
{isAsk &&
borrowsEnabled &&
`${
bank &&
formatValue(
bank
?.scaledInitLiabWeight(bank.price)
.toNumber(),
)
} / ${
bank &&
formatValue(bank.maintLiabWeight.toNumber())
}`}
</Td>
<Td>
{idx % 2 === 0 && bank
? Object.values(LISTING_PRESETS).find((x) => {
return x.initLiabWeight.toFixed(1) === '1.8'
? x.initLiabWeight.toFixed(1) ===
bank?.initLiabWeight
.toNumber()
.toFixed(1) &&
x.reduceOnly === bank.reduceOnly
: x.initLiabWeight.toFixed(1) ===
bank?.initLiabWeight
.toNumber()
.toFixed(1)
})?.preset_name || ''
: ''}
</Td>
<Td xBorder>
{idx % 2 === 0
? symbolToSuggestedPresetName[row.symbol]
? symbolToSuggestedPresetName[row.symbol]
: 'C'
: ''}
</Td>
</TrBody>
)
})}
</tbody>
</Table>
<pre className="mt-6">
{`font color: Red
sell: liquidation fee < price impact && init or main asset weight > 0
buy: liquidation fee < price impact && borrows enabled
strip color: Yellow
sell: target amount <= notional amount of current deposit
buy: target amount <= notional amount of current borrows
strip color: Blue
sell: target amount <= ui deposit weight scale start quote && main asset weight > 0
buy: target amount <= ui borrows weight scale start quote && main asset weight > 0
`}
</pre>
</div>
</div>
) : (
<div className="mt-8 w-full text-center">
Loading... make take up to 60 seconds
</div>
)}
{isAsk &&
borrowsEnabled &&
`${
bank &&
formatValue(
bank?.scaledInitLiabWeight(bank.price).toNumber(),
)
} / ${
bank && formatValue(bank.maintLiabWeight.toNumber())
}`}
</Td>
<Td>
{idx % 2 === 0 && bank
? Object.values(LISTING_PRESETS).find((x) => {
return x.initLiabWeight.toFixed(1) === '1.8'
? x.initLiabWeight.toFixed(1) ===
bank?.initLiabWeight
.toNumber()
.toFixed(1) &&
x.reduceOnly === bank.reduceOnly
: x.initLiabWeight.toFixed(1) ===
bank?.initLiabWeight.toNumber().toFixed(1)
})?.preset_name || ''
: ''}
</Td>
<Td xBorder>
{idx % 2 === 0
? symbolToSuggestedPresetName[row.symbol]
? symbolToSuggestedPresetName[row.symbol]
: 'C'
: ''}
</Td>
</TrBody>
)
})}
</tbody>
</Table>
</div>
<div className="mb-10 ml-20 mr-20 mt-1">
<span>
<h4 className="border-th-bkg-3 px-6 py-4">Annotation Key</h4>
</span>
<Table className="h-full text-xs">
<thead>
<TrHead
style={{ boxShadow: '1px -5px 1px #1d1924', zIndex: 19 }}
className=" bg-th-bkg-2"
>
<Th xBorder className={`text-left`}>
Annotation
</Th>
<Th xBorder className={`text-left`}>
Sell
</Th>
<Th xBorder className={`text-left`}>
Buy
</Th>
</TrHead>
</thead>
<tbody>
<TrBody className="h-10">
<Td>
<div className="flex text-th-error">Red Text</div>
</Td>
<Td>
<div className="flex">
{`liquidation fee < price impact && init or main asset weight > 0`}
</div>
</Td>
<Td>
<div className="flex">
{`liquidation fee < price impact && borrows enabled `}
</div>
</Td>
</TrBody>
<TrBody className="h-10">
<Td>
<div className="flex">
<div className="flex">
<div className="mr-2 h-full"></div>
<div className="ml-auto flex items-center">
<div className="h-5 w-2 bg-[#ffff99]"></div>{' '}
{/* Fixed width and height */}
</div>
</div>
</div>
</Td>
<Td>
<div className="flex">
{`target amount <= notional amount of current deposit`}
</div>
</Td>
<Td>
<div className="flex">
{`target amount <= notional amount of current borrows `}
</div>
</Td>
</TrBody>
<TrBody className="h-10">
<Td>
<div className="flex">
<div className="flex">
<div className="mr-2 h-full"></div>
<div className="ml-auto flex items-center">
<div className="h-5 w-2 bg-[#0066ff]"></div>{' '}
{/* Fixed width and height */}
</div>
</div>
</div>
</Td>
<Td>
<div className="flex">
{`target amount <= ui deposit weight scale start quote && main asset weight > 0`}
</div>
</Td>
<Td>
<div className="flex">
{`target amount <= ui borrows weight scale start quote && main asset weight > 0`}
</div>
</Td>
</TrBody>
</tbody>
</Table>
</div>
</div>
</div>
) : (
<div className="mt-8 w-full text-center">
Loading... make take up to 60 seconds
</div>
)}
</div>
)
}