Skip to content

Commit

Permalink
refactor(dashboard): better overview and slotviz data fetching
Browse files Browse the repository at this point in the history
- Creates composables for Overview and SlotViz, which will eventually replace their respective stores
- Overview and SlotViz data is now fetched in `index.vue` and propped down
- SlotViz updates are handled through update emits
- Introduces proper SSR fetching

See: BEDS-914
  • Loading branch information
LuccaBitfly committed Nov 26, 2024
1 parent 1db1b7c commit 3cbdf1c
Show file tree
Hide file tree
Showing 5 changed files with 199 additions and 63 deletions.
32 changes: 18 additions & 14 deletions frontend/components/dashboard/DashboardValidatorOverview.vue
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
<script setup lang="ts">
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
import { faArrowUpRightFromSquare } from '@fortawesome/pro-solid-svg-icons'
import { useValidatorDashboardOverviewStore } from '~/stores/dashboard/useValidatorDashboardOverviewStore'
import type { ClElValue } from '~/types/api/common'
import {
type NumberOrString, TimeFrames,
} from '~/types/value'
import { totalElClNumbers } from '~/utils/bigMath'
import { DashboardValidatorSubsetModal } from '#components'
import type { VDBOverviewData } from '~/types/api/validator_dashboard'
const { t: $t } = useTranslation()
const { converter } = useValue()
const { overview } = useValidatorDashboardOverviewStore()
const {
overviewData,
} = defineProps<{
overviewData?: VDBOverviewData,
}>()
const formatValueWei = (value: NumberOrString): NumberOrString => {
return converter.value.weiToValue(`${value}`, { fixedDecimalCount: 4 })
Expand All @@ -33,27 +37,27 @@ const createInfo = (
}
const rewardFull = computed(() => converter.value.weiToValue(
totalElCl(overview.value?.rewards.last_30d ?? {
totalElCl(overviewData?.rewards.last_30d ?? {
cl: '0',
el: '0',
}), { addPlus: true }).fullLabel)
const reward = computed(() => converter.value.weiToValue(
totalElCl(overview.value?.rewards.last_30d ?? {
totalElCl(overviewData?.rewards.last_30d ?? {
cl: '0',
el: '0',
}), { addPlus: true }).label)
const validatorsOffline = computed(() => overview.value?.validators.offline ?? 0)
const validatorsOnline = computed(() => overview.value?.validators.online ?? 0)
const validatorsOffline = computed(() => overviewData?.validators.offline ?? 0)
const validatorsOnline = computed(() => overviewData?.validators.online ?? 0)
const validatorsInfos = computed(() =>
[
{
label: $t('dashboard.validator.overview.validators_balance.balance_staked'),
value: formatValueWei(overview.value?.balances.staked_eth ?? 0),
value: formatValueWei(overviewData?.balances.staked_eth ?? 0),
},
{
label: $t('dashboard.validator.overview.validators_balance.balance_effective'),
value: formatValueWei(overview.value?.balances.effective ?? 0),
value: formatValueWei(overviewData?.balances.effective ?? 0),
},
],
)
Expand All @@ -75,25 +79,25 @@ const openValidatorModal = () => {
const efficiencyInfos = computed(() =>
TimeFrames.map(k => ({
label: $t(`statistics.${k}`),
value: formatPercent(overview.value?.efficiency[k] ?? 0),
value: formatPercent(overviewData?.efficiency[k] ?? 0),
})),
)
const rewardsInfos = TimeFrames.map(k =>
createInfo(k, overview.value?.rewards[k] ?? {
createInfo(k, overviewData?.rewards[k] ?? {
cl: '0',
el: '0',
}, formatValueWei),
)
const apr = computed(() => formatPercent(totalElClNumbers(overview.value?.apr.last_30d ?? {
const apr = computed(() => formatPercent(totalElClNumbers(overviewData?.apr.last_30d ?? {
cl: 0,
el: 0,
})),
)
const aprInfos = TimeFrames.map(k =>
createInfo(k, overview.value?.apr[k] ?? {
createInfo(k, overviewData?.apr[k] ?? {
cl: 0,
el: 0,
}, formatToPercent),
Expand Down Expand Up @@ -124,15 +128,15 @@ const aprInfos = TimeFrames.map(k =>
<template #additionalInfo>
{{ $t('dashboard.validator.overview.validators_balance.balance_total') }}
<span class="bold">
{{ formatValueWei(overview?.balances.total ?? 0) }}
{{ formatValueWei(overviewData?.balances.total ?? 0) }}
</span>
</template>
</DashboardValidatorOverviewItem>
<DashboardValidatorOverviewItem
:infos="efficiencyInfos"
:title="$t('dashboard.validator.overview.24h_efficiency')"
>
{{ formatToPercent(overview?.efficiency.last_24h ?? 0) }}
{{ formatToPercent(overviewData?.efficiency.last_24h ?? 0) }}
</DashboardValidatorOverviewItem>
<DashboardValidatorOverviewItem
:infos="rewardsInfos"
Expand Down
25 changes: 12 additions & 13 deletions frontend/components/dashboard/ValidatorSlotViz.vue
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
<script setup lang="ts">
import { orderBy } from 'lodash-es'
import { useValidatorSlotVizStore } from '~/stores/dashboard/useValidatorSlotVizStore'
import type { SlotVizEpoch } from '~/types/api/slot_viz'
import { getGroupLabel } from '~/utils/dashboard/group'
const { t: $t } = useTranslation()
const { dashboardKey } = useDashboardKey()
// TODO: REMOVE THIS
const {
overview, validatorCount,
} = useValidatorDashboardOverviewStore()
Expand All @@ -16,16 +16,17 @@ const {
} = useInterval(12)
const {
refreshSlotViz, slotViz,
} = useValidatorSlotVizStore()
slotVizData,
} = defineProps<{
slotVizData?: SlotVizEpoch[],
}>()
await useAsyncData('validator_dashboard_slot_viz', () =>
refreshSlotViz(dashboardKey.value),
)
const emit = defineEmits<{
(e: 'update', groupIds?: number[]): void,
}>()
watch(
() => [
dashboardKey.value,
selectedGroups.value,
tick.value,
],
Expand All @@ -37,9 +38,8 @@ watch(
) {
resetTick()
}
refreshSlotViz(dashboardKey.value, selectedGroups.value)
emit('update', selectedGroups.value)
},
{ immediate: true },
)
const initiallyHideVisible = computed(() => {
Expand Down Expand Up @@ -83,7 +83,6 @@ watch(
selectAll()
}
},
{ immediate: true },
)
const selectedLabel = computed(() => {
Expand All @@ -103,8 +102,8 @@ const selectedLabel = computed(() => {

<template>
<SlotVizViewer
v-if="slotViz"
:data="slotViz"
v-if="slotVizData"
:data="slotVizData"
:network-info
:timestamp="tick"
:initially-hide-visible
Expand Down
63 changes: 63 additions & 0 deletions frontend/composables/useValidatorDashboardOverview.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import type {
GetValidatorDashboardResponse,
VDBOverviewData,
} from '~/types/api/validator_dashboard'
import type { DashboardKey } from '~/types/dashboard'
import { API_PATH } from '~/types/customFetch'

export function useValidatorDashboardOverview() {
const { fetch } = useCustomFetch()

const overviewData = ref<VDBOverviewData>()
async function fetchOverviewData(key: DashboardKey) {
if (!key) {
throw new Error('No key provided when fetching overview')
}
const res = await fetch<GetValidatorDashboardResponse>(
API_PATH.DASHBOARD_OVERVIEW,
undefined,
{ dashboardKey: key },
)
return res.data
}
/* const hasValidators = computed<boolean>(() => {
if (!overviewData.value?.validators) {
return false
}
return (
!!overviewData.value.validators.online
|| !!overviewData.value.validators.exited
|| !!overviewData.value.validators.offline
|| !!overviewData.value.validators.pending
|| !!overviewData.value.validators.slashed
)
})
const validatorCount = computed(() => {
if (!overviewData.value) {
return undefined
}
if (!overviewData.value.validators) {
return 0
}
return (
overviewData.value.validators.exited
+ overviewData.value.validators.offline
+ overviewData.value.validators.online
+ overviewData.value.validators.pending
+ overviewData.value.validators.slashed
)
})
const hasAbilityCharthistory = computed(() => ({
daily: (overviewData.value?.chart_history_seconds?.daily ?? 0) > 0,
epoch: (overviewData.value?.chart_history_seconds?.epoch ?? 0) > 0,
hourly: (overviewData.value?.chart_history_seconds?.hourly ?? 0) > 0,
weekly: (overviewData.value?.chart_history_seconds?.weekly ?? 0) > 0,
})) */

return {
fetchOverviewData,
overviewData,
}
}
44 changes: 44 additions & 0 deletions frontend/composables/useValidatorSlotViz.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import type {
GetValidatorDashboardSlotVizResponse,
SlotVizEpoch,
} from '~/types/api/slot_viz'
import type { DashboardKey } from '~/types/dashboard'
import { API_PATH } from '~/types/customFetch'

export function useValidatorSlotViz() {
const { fetch } = useCustomFetch()

// State
const slotVizData = ref<SlotVizEpoch[]>() // Renamed `data` to `slotVizData` for clarity

// Actions
async function fetchSlotVizData(dashboardKey: DashboardKey, groupIds?: number[]) {
const query = groupIds?.length ? { group_ids: groupIds.join(',') } : undefined

const res = await fetch<GetValidatorDashboardSlotVizResponse>(
API_PATH.DASHBOARD_SLOTVIZ,
{
headers: {},
query,
},
{ dashboardKey: dashboardKey || 'MQ' }, // If guest dashboard has no validators yet (= empty dashboardKey), load small guest dashboard with 1 validator (MQ)
)
const data = res.data
if (!dashboardKey) {
data.forEach((epoch) => {
epoch.slots?.forEach((slot) => {
Object.assign(slot, {
attestations: undefined, proposal: undefined, slashing: undefined, sync: undefined,
})
})
})
}

return data
}

return {
fetchSlotVizData,
slotVizData,
}
}
Loading

0 comments on commit 3cbdf1c

Please sign in to comment.