Skip to content

Commit

Permalink
Merge pull request #1651 from oasisprotocol/mz/paratimeCard
Browse files Browse the repository at this point in the history
Increase visibility of Sapphire in ParaTimes section
  • Loading branch information
buberdds authored Dec 16, 2024
2 parents 88d289d + 6236fb8 commit 6c925cf
Show file tree
Hide file tree
Showing 5 changed files with 173 additions and 101 deletions.
1 change: 1 addition & 0 deletions .changelog/1651.bugfix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Increase visibility of Sapphire in ParaTimes section
68 changes: 29 additions & 39 deletions src/app/pages/ConsensusDashboardPage/ParaTimesCard.tsx
Original file line number Diff line number Diff line change
@@ -1,53 +1,36 @@
import { FC } from 'react'
import { useTranslation } from 'react-i18next'
import Box from '@mui/material/Box'
import Card from '@mui/material/Card'
import CardHeader from '@mui/material/CardHeader'
import CardContent from '@mui/material/CardContent'
import Grid from '@mui/material/Unstable_Grid2'
import { styled } from '@mui/material/styles'
import { Layer, Runtime } from '../../../oasis-nexus/api'
import { COLORS } from '../../../styles/theme/colors'
import { CardHeaderWithCounter } from '../../components/CardHeaderWithCounter'
import { isNotOnHiddenLayer, RouteUtils } from '../../utils/route-utils'
import { SearchScope } from '../../../types/searchScope'
import { EnabledRuntimePreview, InactiveRuntimePreview } from './RuntimePreview'

const StyledBox = styled(Box)(({ theme }) => ({
display: 'flex',
[theme.breakpoints.up('md')]: {
paddingRight: theme.spacing(4),
paddingLeft: theme.spacing(4),
},
[theme.breakpoints.down('md')]: {
flexDirection: 'column',
},
'> div:not(:last-child)': {
[theme.breakpoints.down('md')]: {
paddingBottom: theme.spacing(4),
borderBottom: `1px solid ${COLORS.grayMediumLight}`,
},
[theme.breakpoints.up('md')]: {
paddingRight: theme.spacing(5),
marginRight: theme.spacing(5),
borderRight: `1px solid ${COLORS.grayMediumLight}`,
},
},
}))
import { EnabledRuntimePreview, DisabledRuntimePreview } from './RuntimePreview'

function shouldIncludeLayer(layer: Layer) {
return layer !== Layer.consensus && isNotOnHiddenLayer({ layer })
}

const StyledInnerGrid = styled(Grid)(({ theme }) => ({
[theme.breakpoints.down('md')]: {
paddingTop: 0,
},
}))

type ParaTimesCardProps = { scope: SearchScope }

export const ParaTimesCard: FC<ParaTimesCardProps> = ({ scope }) => {
const { t } = useTranslation()
const { network } = scope
const { enabled, disabled } = RouteUtils.getAllLayersForNetwork(network)
const enabledOasisRuntimes = enabled.filter(shouldIncludeLayer) as Runtime[]
const disabledOasisRuntimes = disabled.filter(shouldIncludeLayer) as Runtime[]
const runtimesNumber = enabledOasisRuntimes.length + disabledOasisRuntimes.length

const enabledRuntimes = enabled.filter(shouldIncludeLayer) as Runtime[]
const disabledRuntimes = disabled.filter(shouldIncludeLayer) as Runtime[]
const runtimesNumber = enabledRuntimes.length + disabledRuntimes.length
const [firstEnabledRuntime, ...restEnabledRuntimes] = enabledRuntimes
return (
<Card>
<CardHeader
Expand All @@ -62,16 +45,23 @@ export const ParaTimesCard: FC<ParaTimesCardProps> = ({ scope }) => {
}
/>
<CardContent>
<StyledBox>
{!!enabledOasisRuntimes.length &&
enabledOasisRuntimes.map(runtime => (
<EnabledRuntimePreview key={runtime} network={scope.network} runtime={runtime} />
))}
{!!disabledOasisRuntimes.length &&
disabledOasisRuntimes.map(runtime => (
<InactiveRuntimePreview key={runtime} network={scope.network} runtime={runtime} />
))}
</StyledBox>
<Grid container spacing={5}>
<Grid xs={12} md={6}>
<EnabledRuntimePreview prominentItem network={scope.network} runtime={firstEnabledRuntime} />
</Grid>
<Grid xs={12} md={6} container>
<StyledInnerGrid xs={12} md={8}>
{!!restEnabledRuntimes.length &&
restEnabledRuntimes.map(runtime => (
<EnabledRuntimePreview key={runtime} network={scope.network} runtime={runtime} />
))}
</StyledInnerGrid>
<StyledInnerGrid xs={12} md={4}>
{!!disabledRuntimes.length &&
disabledRuntimes.map(runtime => <DisabledRuntimePreview key={runtime} runtime={runtime} />)}
</StyledInnerGrid>
</Grid>
</Grid>
</CardContent>
</Card>
)
Expand Down
178 changes: 126 additions & 52 deletions src/app/pages/ConsensusDashboardPage/RuntimePreview.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { FC, useState } from 'react'
import { FC, ReactNode, useState } from 'react'
import { Link as RouterLink } from 'react-router-dom'
import { useTranslation } from 'react-i18next'
import Box from '@mui/material/Box'
Expand Down Expand Up @@ -42,6 +42,7 @@ const StyledBox = styled(Box)(() => ({
borderRadius: '12px',
height: '180px',
display: 'flex',
flex: 1,
justifyContent: 'center',
alignItems: 'center',
boxShadow: '0px 34px 24px -9px #324DAB1F',
Expand All @@ -58,12 +59,39 @@ const StyledTypography = styled(Typography)(() => ({
alignItems: 'center',
}))

const StyledDisabledRuntime = styled(Box)(({ theme }) => ({
display: 'flex',
gap: 3,
paddingTop: theme.spacing(3),
flexDirection: 'row',
alignItems: 'center',
[theme.breakpoints.between('md', 'xl')]: {
flexDirection: 'column',
alignItems: 'flex-start',
},
}))

const StyledEnabledRuntime = styled(Box)(({ theme }) => ({
height: '100%',
paddingTop: theme.spacing(3),
paddingBottom: theme.spacing(3),
[theme.breakpoints.down('md')]: {
paddingBottom: theme.spacing(5),
borderBottom: `1px solid ${COLORS.grayMediumLight}`,
},
[theme.breakpoints.up('md')]: {
paddingRight: theme.spacing(5),
borderRight: `1px solid ${COLORS.grayMediumLight}`,
},
}))

type RuntimeProps = {
prominentItem?: boolean
network: Network
runtime: Runtime
}

export const EnabledRuntimePreview: FC<RuntimeProps> = ({ network, runtime }) => {
export const EnabledRuntimePreview: FC<RuntimeProps> = ({ prominentItem, network, runtime }) => {
const query = useGetRuntimeStatus(network, runtime)
const { outOfDate } = useRuntimeFreshness({
network,
Expand All @@ -73,6 +101,7 @@ export const EnabledRuntimePreview: FC<RuntimeProps> = ({ network, runtime }) =>

return (
<RuntimePreview
prominentItem={prominentItem}
network={network}
runtime={runtime}
status={{
Expand All @@ -84,8 +113,23 @@ export const EnabledRuntimePreview: FC<RuntimeProps> = ({ network, runtime }) =>
)
}

export const InactiveRuntimePreview: FC<RuntimeProps> = ({ network, runtime }) => {
return <RuntimePreview network={network} runtime={runtime} />
type DisabledRuntimePreviewProps = {
runtime: Runtime
}

export const DisabledRuntimePreview: FC<DisabledRuntimePreviewProps> = ({ runtime }) => {
const { t } = useTranslation()
const layerLabels = getLayerLabels(t)
const runtimeLabel = layerLabels[runtime]

return (
<StyledDisabledRuntime>
<StyledTypography>{runtimeLabel}</StyledTypography>
<Box>
<RuntimeStatusIcon status="inactive" />
</Box>
</StyledDisabledRuntime>
)
}

type RuntimePreviewProps = RuntimeProps & {
Expand All @@ -98,15 +142,15 @@ type RuntimePreviewProps = RuntimeProps & {

type Panels = 'transactions' | 'accounts'

const RuntimePreview: FC<RuntimePreviewProps> = ({ network, runtime, status }) => {
const RuntimePreview: FC<RuntimePreviewProps> = ({ prominentItem, network, runtime, status }) => {
const { t } = useTranslation()
const [panel, setPanel] = useState<Panels>('transactions')
const layerLabels = getLayerLabels(t)
const runtimeLabel = layerLabels[runtime]
const dashboardLink = RouteUtils.getDashboardRoute({ network, layer: runtime })
const runtimeStatus = status ? (status.outOfDate ? 'outdated' : 'stable') : 'inactive'
return (
<Box sx={{ flex: 1, paddingY: 3 }}>
<StyledEnabledRuntime>
<Box sx={{ marginBottom: 4 }}>
<StyledTypography>
{status ? (
Expand Down Expand Up @@ -145,57 +189,60 @@ const RuntimePreview: FC<RuntimePreviewProps> = ({ network, runtime, status }) =
<dt>{t('paratimes.nodes')} </dt>
<dd>{status?.activeNodes ? t('paratimes.activeNodes', { nodes: status?.activeNodes }) : '-'} </dd>
</StyledList>
<StyledBox>
<Box gap={3} sx={{ flex: 1, display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
{status && (
<Box sx={{ width: '100%' }}>
{panel === 'transactions' && (
<TransactionsChartCard
scope={{
layer: runtime,
network,
}}
chartDuration={ChartDuration.TODAY}
/>
)}
{panel === 'accounts' && (
<ActiveAccounts
scope={{
layer: runtime,
network,
}}
chartDuration={ChartDuration.TODAY}
/>
)}
</Box>
)}
{!status && (
<>
<FilterNoneIcon sx={{ color: COLORS.brandDark, fontSize: '33px' }} />
{t('paratimes.noData')}
</>
<Box sx={{ display: 'flex', gap: 3 }}>
<ChartsContainer status={status}>
{panel === 'transactions' && (
<TransactionsChartCard
scope={{
layer: runtime,
network,
}}
chartDuration={ChartDuration.TODAY}
/>
)}
</Box>
</StyledBox>
<Box sx={{ display: 'flex', justifyContent: 'center', paddingTop: 3 }}>
{status && (
<>
<PanelButton
activePanel={panel}
ariaLabel={t('common.transactions')}
panel="transactions"
setPanel={setPanel}
{panel === 'accounts' && (
<ActiveAccounts
scope={{
layer: runtime,
network,
}}
chartDuration={ChartDuration.TODAY}
/>
<PanelButton
activePanel={panel}
ariaLabel={t('account.listTitle')}
panel="accounts"
setPanel={setPanel}
)}
</ChartsContainer>
{prominentItem && (
<ChartsContainer status={status}>
<ActiveAccounts
scope={{
layer: runtime,
network,
}}
chartDuration={ChartDuration.TODAY}
/>
</>
</ChartsContainer>
)}
</Box>
</Box>
{!prominentItem && (
<Box sx={{ display: 'flex', justifyContent: 'center', paddingTop: 3 }}>
{status && (
<>
<PanelButton
activePanel={panel}
ariaLabel={t('common.transactions')}
panel="transactions"
setPanel={setPanel}
/>
<PanelButton
activePanel={panel}
ariaLabel={t('account.listTitle')}
panel="accounts"
setPanel={setPanel}
/>
</>
)}
</Box>
)}
</StyledEnabledRuntime>
)
}

Expand All @@ -219,3 +266,30 @@ const PanelButton: FC<PanelButtonProps> = ({ activePanel, ariaLabel, panel, setP
</>
)
}

type ChartsContainerProps = {
children: ReactNode
status?: {
activeNodes: number | undefined
latestBlock: number | undefined
outOfDate: boolean | undefined
}
}

const ChartsContainer: FC<ChartsContainerProps> = ({ children, status }) => {
const { t } = useTranslation()

return (
<StyledBox>
<Box gap={3} sx={{ flex: 1, display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
{status && <Box sx={{ width: '100%' }}>{children}</Box>}
{!status && (
<>
<FilterNoneIcon sx={{ color: COLORS.brandDark, fontSize: '33px' }} />
{t('paratimes.noData')}
</>
)}
</Box>
</StyledBox>
)
}
18 changes: 10 additions & 8 deletions src/app/utils/route-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { isStableDeploy, specialScopePaths } from '../../config'
import { getSearchTermFromRequest } from '../components/Search/search-utils'
import type { HasLayer } from '../../types/layers'
import { toChecksumAddress } from '@ethereumjs/util'
import { orderByLayer } from '../../types/layers'

export const fixedNetwork = process.env.REACT_APP_FIXED_NETWORK as Network | undefined
export const fixedLayer = process.env.REACT_APP_FIXED_LAYER as Layer | undefined
Expand Down Expand Up @@ -185,14 +186,15 @@ export abstract class RouteUtils {
static getAllLayersForNetwork(network: Network): { enabled: Layer[]; disabled: Layer[] } {
const enabled: Layer[] = []
const disabled: Layer[] = []

Object.values(Layer).forEach(layer => {
if ((!fixedLayer || layer === fixedLayer) && RouteUtils.ENABLED_LAYERS_FOR_NETWORK[network][layer]) {
enabled.push(layer)
} else {
disabled.push(layer)
}
})
Object.values(Layer)
.sort(orderByLayer)
.forEach(layer => {
if ((!fixedLayer || layer === fixedLayer) && RouteUtils.ENABLED_LAYERS_FOR_NETWORK[network][layer]) {
enabled.push(layer)
} else {
disabled.push(layer)
}
})

return {
enabled,
Expand Down
9 changes: 7 additions & 2 deletions src/types/layers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,13 @@ const layerOrder: Record<Layer, number> = {
[Layer.pontusxtest]: 6,
}

export const orderByLayer = (itemA: HasLayer, itemB: HasLayer): number =>
layerOrder[itemA.layer] - layerOrder[itemB.layer]
export function orderByLayer(itemA: Layer, itemB: Layer): number
export function orderByLayer(itemA: HasLayer, itemB: HasLayer): number
export function orderByLayer(itemA: Layer | HasLayer, itemB: Layer | HasLayer): number {
const layerA = typeof itemA === 'string' ? itemA : itemA.layer
const layerB = typeof itemB === 'string' ? itemB : itemB.layer
return layerOrder[layerA] - layerOrder[layerB]
}

const layersWithEncryptedTransactions: Layer[] = [Layer.sapphire, Layer.cipher]

Expand Down

0 comments on commit 6c925cf

Please sign in to comment.