Skip to content

Commit

Permalink
update(validator dashboard): validator subset states (#654)
Browse files Browse the repository at this point in the history
* update and map new validator states in the validator subset modal
* count based on the groups based and only default to the row data
Bids 3232
  • Loading branch information
MauserBitfly authored Aug 5, 2024
1 parent e0d9c21 commit 575f079
Show file tree
Hide file tree
Showing 10 changed files with 251 additions and 102 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import { useValidatorDashboardOverviewStore } from '~/stores/dashboard/useValida
import { DAHSHBOARDS_ALL_GROUPS_ID } from '~/types/dashboard'
import { getGroupLabel } from '~/utils/dashboard/group'
import { SummaryTimeFrames, type SummaryChartFilter, type SummaryTableVisibility, type SummaryTimeFrame } from '~/types/dashboard/summary'
import type { DashboardTableSummaryValidators } from '#build/components'
const { dashboardKey, isPublic } = useDashboardKey()
Expand Down
69 changes: 13 additions & 56 deletions frontend/components/dashboard/table/SummaryValidators.vue
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
<script setup lang="ts">
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
import {
faArrowUpRightFromSquare,
faPowerOff
faArrowUpRightFromSquare
} from '@fortawesome/pro-solid-svg-icons'
import type { DashboardValidatorContext, SummaryTimeFrame } from '~/types/dashboard/summary'
import { DashboardValidatorSubsetModal } from '#components'
import { getGroupLabel } from '~/utils/dashboard/group'
import type { DashboardKey } from '~/types/dashboard'
import type { VDBSummaryTableRow } from '~/types/api/validator_dashboard'
import type { SummaryValidatorsIconRowInfo, ValidatorSummaryIconRowKey } from '~/types/validator'
interface Props {
row: VDBSummaryTableRow,
Expand Down Expand Up @@ -46,8 +46,9 @@ const groupName = computed(() => {
})
const mapped = computed(() => {
const list: { count: number, key: string }[] = []
const addCount = (key: string, count?: number) => {
const list: SummaryValidatorsIconRowInfo[] = []
const validatorIcons: SummaryValidatorsIconRowInfo[] = []
const addCount = (key: ValidatorSummaryIconRowKey, count?: number) => {
if (count) {
list.push({ count, key })
}
Expand All @@ -58,11 +59,13 @@ const mapped = computed(() => {
addCount('offline', props.row?.validators.offline)
addCount('exited', props.row?.validators.exited)
}
// for the total percentage we ignore the exited validators
const total = props.row?.validators.offline + props.row?.validators.online
return {
list,
total
total,
validatorIcons
}
})
Expand All @@ -73,13 +76,11 @@ const mapped = computed(() => {
<template v-if="!isTooltip" #tooltip>
<DashboardTableSummaryValidators v-bind="props" :absolute="!props.absolute" :is-tooltip="true" />
</template>
<div v-for="status in mapped.list" :key="status.key" class="status" :class="status.key">
<div class="icon">
<FontAwesomeIcon :icon="faPowerOff" />
</div>
<BcFormatNumber v-if="absolute" :value="status.count" />
<BcFormatPercent v-else :value="status.count" :base="mapped.total" />
</div>
<DashboardTableSummaryValidatorsIconRow
:icons="mapped.list"
:total="mapped.total"
:absolute="absolute"
/>
</BcTooltip>
<FontAwesomeIcon
v-if="!isTooltip"
Expand Down Expand Up @@ -112,50 +113,6 @@ const mapped = computed(() => {
align-items: center;
flex-wrap: wrap;
gap: var(--padding-small);
.status {
display: flex;
align-items: center;
gap: 3px;
.icon {
display: flex;
align-items: center;
justify-content: center;
width: 14px;
height: 14px;
border-radius: 50%;
background-color: var(--text-color-disabled);
svg {
height: 8px;
width: 8px;
}
}
&.online {
.icon {
background-color: var(--positive-color);
color: var(--positive-contrast-color);
}
span {
color: var(--positive-color);
}
}
&.offline {
.icon {
background-color: var(--negative-color);
color: var(--negative-contrast-color);
}
span {
color: var(--negative-color);
}
}
}
}
.popout {
Expand Down
74 changes: 74 additions & 0 deletions frontend/components/dashboard/table/SummaryValidatorsIconRow.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
<script setup lang="ts">
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
import {
faPowerOff
} from '@fortawesome/pro-solid-svg-icons'
import type { SummaryValidatorsIconRowInfo } from '~/types/validator'
interface Props {
icons: SummaryValidatorsIconRowInfo[]
total?: number
absolute: boolean
}
const props = defineProps<Props>()
const combinedTotal = computed<number>(() => props.total ?? props.icons?.reduce((sum, icon) => sum + icon.count, 0) ?? 0)
</script>
<template>
<div v-for="status in icons" :key="status.key" class="status" :class="status.key">
<div class="icon">
<FontAwesomeIcon :icon="faPowerOff" />
</div>
<BcFormatNumber v-if="absolute" :value="status.count" />
<BcFormatPercent v-else :value="status.count" :base="combinedTotal" />
</div>
</template>

<style lang="scss" scoped>
@use '~/assets/css/utils.scss';
.status {
display: flex;
align-items: center;
gap: 3px;
.icon {
display: flex;
align-items: center;
justify-content: center;
width: 14px;
height: 14px;
border-radius: 50%;
background-color: var(--text-color-disabled);
svg {
height: 8px;
width: 8px;
}
}
&.online {
.icon {
background-color: var(--positive-color);
color: var(--positive-contrast-color);
}
span {
color: var(--positive-color);
}
}
&.offline {
.icon {
background-color: var(--negative-color);
color: var(--negative-contrast-color);
}
span {
color: var(--negative-color);
}
}
}
</style>
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,10 @@ function mapDutyLabel (dutyObjects?: number[]) {
return $t('dashboard.validator.subset_dialog.got_slashed') + ':'
}
}
function mapDutyLinks (dutyObjects?: number[]) {
function mapDutyLinks (dutyObjects?: number[]): { to?: string, label: string }[] {
if (!dutyObjects) {
return
return []
}
const links: { to: string, label: string }[] = []
let path = ''
let formatValue = true
switch (props.category) {
Expand All @@ -96,8 +95,11 @@ function mapDutyLinks (dutyObjects?: number[]) {
to: `${path}${o}`,
label: `${formatValue ? formatNumber(o) : o}`
}))
} else {
return dutyObjects.map(o => ({
label: `${formatValue ? formatNumber(o) : o}`
}))
}
return links
}
</script>
Expand All @@ -112,13 +114,14 @@ function mapDutyLinks (dutyObjects?: number[]) {
<BcLink :to="`/validator/${v.index}`" target="_blank" class="link">
{{ v.index }}
</BcLink>
<template v-if="mapDutyLabel(v.duty_objects)">
<template v-if="v.duty_objects?.length">
<span class="round-brackets">
<span class="label">{{ mapDutyLabel(v.duty_objects) }}</span>
<template v-for="link in mapDutyLinks(v.duty_objects)" :key="link.label">
<BcLink :to="link.to" target="_blank" class="link">
<BcLink v-if="link.to" :to="link.to" target="_blank" class="link">
{{ link.label }}
</BcLink>
<span v-else>{{ link.label }}</span>
<span>, </span>

</template>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
import type { ValidatorSubsetCategory } from '~/types/validator'
import type { VDBSummaryValidator } from '~/types/api/validator_dashboard'
import type { SlotVizCategories } from '~/types/dashboard/slotViz'
import { countSummaryValidatorDuties } from '~/utils/dashboard/validator'
interface Props {
category: ValidatorSubsetCategory,
Expand Down Expand Up @@ -76,14 +77,16 @@ const icon = computed(() => {
return { icon, className, slotVizCategory }
})
const count = computed(() => countSummaryValidatorDuties(props.validators, props.category))
</script>

<template>
<div class="subset--list-header">
<FontAwesomeIcon v-if="icon.icon" :icon="icon.icon" :class="icon.className" />
<SlotVizIcon v-else-if="icon.slotVizCategory" :icon="icon.slotVizCategory" :class="icon.className" />
<span>{{ $t(`dashboard.validator.subset_dialog.category.${category}`) }}</span>
<span> ({{ validators.length }})</span>
<span> (<BcFormatNumber :value="count" />)</span>
</div>
</template>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
import { uniqBy } from 'lodash-es'
import type { DashboardValidatorContext, SummaryTimeFrame } from '~/types/dashboard/summary'
import type { DashboardKey } from '~/types/dashboard'
import type { ValidatorSubset } from '~/types/validator'
import type { ValidatorSubset, ValidatorSubsetCategory } from '~/types/validator'
import { sortSummaryValidators } from '~/utils/dashboard/validator'
import { API_PATH } from '~/types/customFetch'
import { type InternalGetValidatorDashboardSummaryValidatorsResponse, type VDBGroupSummaryData, type VDBSummaryTableRow, type VDBSummaryValidator, type VDBSummaryValidatorsData } from '~/types/api/validator_dashboard'
Expand Down Expand Up @@ -77,7 +77,7 @@ watch(props, async (p) => {
}
}, { immediate: true })
const mapped = computed<ValidatorSubset[]>(() => {
const subsets = computed<ValidatorSubset[]>(() => {
const sortAndFilter = (validators:VDBSummaryValidator[]):VDBSummaryValidator[] => {
if (!filter.value) {
return sortSummaryValidators(validators)
Expand All @@ -98,14 +98,57 @@ const mapped = computed<ValidatorSubset[]>(() => {
category: sub.category,
validators: sortAndFilter(sub.validators)
})).filter(s => !!s.validators.length)
if (filtered.length && !filter.value) {
const all:ValidatorSubset = {
category: 'all',
validators: []
// Let's combine what needs to be combined
if (filtered.length > 1) {
if (props.value?.context === 'group' || props.value?.context === 'dashboard') {
const all:ValidatorSubset = {
category: 'all',
validators: []
}
all.validators = sortSummaryValidators(uniqBy(filtered.reduce((list, sub) => list.concat(sub.validators.map(v => ({ index: v.index, duty_objects: [] }))), all.validators), 'index'))
filtered.splice(0, 0, all)
}
// we need to split up the withdrawn and withrawing categories into exited and slashed and not show them individually
const withdrawnIndex = filtered.findIndex(s => s.category === 'withdrawn')
const withdrawn = withdrawnIndex >= 0 ? filtered.splice(withdrawnIndex, 1)[0] : undefined
const withdrawingIndex = filtered.findIndex(s => s.category === 'withdrawing')
const withdrawing = withdrawingIndex >= 0 ? filtered.splice(withdrawingIndex, 1)[0] : undefined
if (withdrawn?.validators.length || withdrawing?.validators.length) {
// a withrawn/withrawing validator can either be in the exited or slashed group
const categories: ValidatorSubsetCategory[] = ['exited', 'slashed']
categories.forEach((category) => {
const index = filtered.findIndex(s => s.category === category)
if (index >= 0) {
const baseSubset = filtered[index]
const xWithdrawn: ValidatorSubset = {
category: `${category}_withdrawn` as ValidatorSubsetCategory,
validators: []
}
const xWithdrawing: ValidatorSubset = {
category: `${category}_withdrawing`as ValidatorSubsetCategory,
validators: []
}
const subsets = [[withdrawn, xWithdrawn], [withdrawing, xWithdrawing]]
baseSubset.validators.forEach((v) => {
subsets.forEach(([origin, merged]) => {
if (origin?.validators.find(sV => v.index === sV.index)) {
merged?.validators.push({ ...v, duty_objects: [] })
}
})
})
subsets.forEach(([_origin, merged]) => {
if (merged?.validators.length) {
filtered.splice(index + 1, 0, merged)
}
})
}
})
}
all.validators = sortSummaryValidators(uniqBy(filtered.reduce((list, sub) => list.concat(sub.validators), all.validators), 'index'))
filtered.splice(0, 0, all)
return filtered
}
return filtered
})
Expand All @@ -120,12 +163,13 @@ const mapped = computed<ValidatorSubset[]>(() => {
:context="props.context"
:sub-title="props.groupName || props.dashboardName"
:summary="props.summary"
:subsets="subsets"
/>
<BcContentFilter v-model="filter" :search-placeholder="$t('common.index')" @filter-changed="(f:string)=>filter=f" />
</div>

<Accordion :active-index="0" class="accordion basic">
<AccordionTab v-for="subset in mapped" :key="subset.category">
<Accordion :active-index="-1" class="accordion basic">
<AccordionTab v-for="subset in subsets" :key="subset.category">
<template #headericon>
<FontAwesomeIcon :icon="faCaretRight" />
</template>
Expand All @@ -134,8 +178,8 @@ const mapped = computed<ValidatorSubset[]>(() => {
</template>
<DashboardValidatorSubsetList :category="subset.category" :validators="subset.validators" />
</AccordionTab>
<BcLoadingSpinner :loading="isLoading" alignment="center" class="spinner" />
</Accordion>
<BcLoadingSpinner :loading="isLoading" alignment="center" class="spinner" />
</div>
</template>

Expand Down Expand Up @@ -174,7 +218,7 @@ const mapped = computed<ValidatorSubset[]>(() => {
position: relative;
flex-grow: 1;
max-height: 453px;
min-height: 200px;
min-height: 453px;
overflow-y: auto;
overflow-x: hidden;
word-break: break-all;
Expand Down
Loading

0 comments on commit 575f079

Please sign in to comment.