add pinned mode

This commit is contained in:
liangping 2021-11-13 17:03:49 +08:00
parent cfa55105a1
commit d618eae534
6 changed files with 305 additions and 20 deletions

View File

@ -52,8 +52,8 @@ export default class ChainFetch {
return this.get('/blocks/latest', config).then(data => Block.create(data)) return this.get('/blocks/latest', config).then(data => Block.create(data))
} }
async getBlockByHeight(height) { async getBlockByHeight(height, config = null) {
return this.get(`/blocks/${height}`).then(data => Block.create(data)) return this.get(`/blocks/${height}`, config).then(data => Block.create(data))
} }
async getSlashingSigningInfo() { async getSlashingSigningInfo() {

View File

@ -126,6 +126,24 @@ const router = new VueRouter({
], ],
}, },
}, },
{
path: '/:chain/uptime/my',
name: 'uptime',
component: () => import('@/views/UptimeMyValidators.vue'),
meta: {
pageTitle: 'Uptime',
breadcrumb: [
{
text: 'Uptime',
active: true,
},
{
text: 'My Validators',
active: true,
},
],
},
},
{ {
path: '/:chain/account/:address', path: '/:chain/account/:address',
name: 'chain-account', name: 'chain-account',

View File

@ -13,6 +13,12 @@
no-body no-body
class="mb-1" class="mb-1"
> >
<b-button
:href="`./uptime/my`"
variant="primary"
>
Browse favourate only
</b-button>
<b-form-input <b-form-input
v-model="query" v-model="query"
placeholder="Keywords to filter validators" placeholder="Keywords to filter validators"
@ -26,8 +32,13 @@
md="4" md="4"
class="text-truncate" class="text-truncate"
> >
<span class="d-inline-block text-truncate font-weight-bold align-bottom">{{ index+1 }} {{ x.validator.moniker }}</span> <b-form-checkbox
<template> v-model="pinned"
:value="`${chain}#${x.address}`"
class="custom-control-warning"
@change="pinValidator(`${chain}#${x.address}`)"
><span class="d-inline-block text-truncate font-weight-bold align-bottom">{{ index+1 }} {{ x.validator.moniker }}</span>
</b-form-checkbox>
<div class="d-flex justify-content-between align-self-stretch flex-wrap"> <div class="d-flex justify-content-between align-self-stretch flex-wrap">
<div <div
v-for="(b,i) in blocks" v-for="(b,i) in blocks"
@ -43,7 +54,6 @@
</router-link> </router-link>
</div> </div>
</div> </div>
</template>
</b-col> </b-col>
</b-row> </b-row>
</b-card> </b-card>
@ -52,7 +62,7 @@
<script> <script>
import { import {
BRow, BCol, VBTooltip, BFormInput, BCard, BAlert, BRow, BCol, VBTooltip, BFormInput, BCard, BAlert, BFormCheckbox, BButton,
} from 'bootstrap-vue' } from 'bootstrap-vue'
import { import {
@ -66,12 +76,18 @@ export default {
BFormInput, BFormInput,
BCard, BCard,
BAlert, BAlert,
BButton,
BFormCheckbox,
}, },
directives: { directives: {
'b-tooltip': VBTooltip, 'b-tooltip': VBTooltip,
}, },
data() { data() {
const { chain } = this.$route.params
const pinned = localStorage.getItem('pinned') ? localStorage.getItem('pinned').split(',') : ''
return { return {
pinned,
chain,
query: '', query: '',
validators: [], validators: [],
missing: {}, missing: {},
@ -108,6 +124,9 @@ export default {
clearInterval(this.timer) clearInterval(this.timer)
}, },
methods: { methods: {
pinValidator() {
localStorage.setItem('pinned', this.pinned)
},
initBlocks() { initBlocks() {
this.$http.getLatestBlock().then(d => { this.$http.getLatestBlock().then(d => {
const { height } = d.block.last_commit const { height } = d.block.last_commit

View File

@ -0,0 +1,182 @@
<template>
<div class="px-0">
<b-card>
<b-card-title class="text-uppercase">
{{ chain }}
</b-card-title>
<b-alert
variant="danger"
:show="syncing"
>
<div class="alert-body">
<span>No new block is produced since <strong>{{ latestTime }}</strong> </span>
</div>
</b-alert>
<b-row>
<b-col
v-for="(x,index) in uptime"
:key="index"
sm="12"
class="text-truncate"
>
<b-form-checkbox
v-model="pinned"
:value="`${chain}#${x.address}`"
class="custom-control-warning"
@change="pinValidator(`${chain}#${x.address}`)"
>
<span class="d-inline-block text-truncate font-weight-bold align-bottom"> {{ x.validator.moniker }}</span>
</b-form-checkbox>
<div class="d-flex justify-content-between align-self-stretch flex-wrap">
<div
v-for="(b,i) in blocks"
:key="i"
style="width:1.5%;"
><router-link :to="`./blocks/${b.height}`">
<div
v-b-tooltip.hover.v-second
:title="b.height"
:class="b.sigs && b.sigs[x.address] ? b.sigs[x.address] : 'bg-light-success'"
class="m-auto"
>&nbsp;</div>
</router-link>
</div>
</div>
</b-col>
</b-row>
</b-card>
</div>
</template>
<script>
import {
BRow, BCol, VBTooltip, BCard, BAlert, BCardTitle, BFormCheckbox,
} from 'bootstrap-vue'
import {
getLocalChains, timeIn, toDay,
} from '@/libs/data'
export default {
name: 'Blocks',
components: {
BRow,
BCol,
BCard,
BAlert,
BCardTitle,
BFormCheckbox,
},
directives: {
'b-tooltip': VBTooltip,
},
props: {
chain: {
type: String,
default: null,
},
validators: {
type: Array,
default: () => [],
},
},
data() {
const chains = getLocalChains()
const pinned = localStorage.getItem('pinned') ? localStorage.getItem('pinned').split(',') : ''
return {
pinned,
config: chains[this.chain],
missing: {},
blocks: Array.from('0'.repeat(50)).map(x => ({ sigs: {}, height: Number(x) })),
syncing: false,
latestTime: '',
}
},
computed: {
uptime() {
const vals = this.validators
return vals
},
},
created() {
this.initBlocks()
},
beforeDestroy() {
this.blocks = [] // clear running tasks if it is not finish
this.syncing = false
clearInterval(this.timer)
},
methods: {
pinValidator() {
localStorage.setItem('pinned', this.pinned)
},
initBlocks() {
this.$http.getLatestBlock(this.config).then(d => {
const { height } = d.block.last_commit
if (timeIn(d.block.header.time, 3, 'm')) {
this.syncing = true
} else {
this.syncing = false
}
this.latestTime = toDay(d.block.header.time, 'long')
const blocks = []
// update height
let promise = Promise.resolve()
for (let i = height - 1; i > height - 50; i -= 1) {
blocks.unshift({ sigs: {}, height: i > 0 ? i : 0 })
if (i > height - 48 && i > 0) {
promise = promise.then(() => new Promise(resolve => {
this.fetch_status(i, resolve)
}))
}
}
const sigs = this.initColor()
d.block.last_commit.signatures.forEach(x => {
if (x.validator_address) sigs[x.validator_address] = 'bg-success'
})
blocks.push({ sigs, height })
this.blocks = blocks
this.timer = setInterval(this.fetch_latest, 6000)
})
},
initColor() {
const sigs = {}
this.validators.forEach(x => {
sigs[x.address] = 'bg-danger'
})
return sigs
},
fetch_status(height, resolve) {
const block = this.blocks.find(b => b.height === height)
if (block) {
this.$http.getBlockByHeight(height, this.config).then(res => {
resolve()
const sigs = this.initColor()
res.block.last_commit.signatures.forEach(x => {
if (x.validator_address) sigs[x.validator_address] = 'bg-success'
})
this.$set(block, 'sigs', sigs)
})
}
},
fetch_latest() {
this.$http.getLatestBlock(this.config).then(res => {
const sigs = this.initColor()
res.block.last_commit.signatures.forEach(x => {
if (x.validator_address) sigs[x.validator_address] = 'bg-success'
})
const block = this.blocks.find(b => b[1] === res.block.last_commit.height)
if (typeof block === 'undefined') { // mei
// this.$set(block, 0, typeof sigs !== 'undefined')
if (this.blocks.length >= 50) this.blocks.shift()
this.blocks.push({ sigs, height: res.block.last_commit.height })
}
})
},
},
}
</script>
<style></style>

View File

@ -0,0 +1,66 @@
<template>
<div class="container-md px-0">
<b-row>
<b-col
v-for="(x,index) in Object.keys(chainVals)"
:key="index"
sm="12"
md="4"
class="text-truncate"
>
<uptime-my-chain-blocks
:chain="x"
:validators="chainVals[x]"
/>
</b-col>
</b-row>
</div>
</template>
<script>
import {
BRow, BCol, VBTooltip,
} from 'bootstrap-vue'
import { consensusPubkeyToHexAddress, getCachedValidators } from '@/libs/data'
import UptimeMyChainBlocks from './UptimeMyChainBlocks.vue'
export default {
components: {
BRow,
BCol,
UptimeMyChainBlocks,
},
directives: {
'b-tooltip': VBTooltip,
},
data() {
const pinned = (localStorage.getItem('pinned') || '').split(',').map(x => x.split('#')).reduce((a1, b) => {
const a = a1
if (a[b[0]]) {
a[b[0]].push(b[1])
} else {
a[b[0]] = [b[1]]
}
return a
}, {})
const chainVals = {}
Object.keys(pinned).forEach(x => {
const cached = JSON.parse(getCachedValidators(x))
const validators = []
pinned[x].forEach(address => {
const val = cached.find(v => address === consensusPubkeyToHexAddress(v.consensus_pubkey))
validators.push({ address, validator: val.description })
})
chainVals[x] = validators
})
return {
chainVals,
}
},
}
</script>
<style></style>

View File

@ -48,7 +48,7 @@ module.exports = {
devServer: { devServer: {
proxy: { proxy: {
'/api': { '/api': {
target: 'https://lcd-cosmos.cosmostation.io/', target: 'https://cosmos.api.ping.pub/',
changeOrigin: true, changeOrigin: true,
pathRewrite: { pathRewrite: {
'^/api': '', '^/api': '',