Merge pull request #13 from ping-pub/v3-single
atomatically load latest
This commit is contained in:
commit
58b086b744
@ -86,8 +86,8 @@ chainStore.$subscribe((m, s) => {
|
||||
<div
|
||||
class="capitalize whitespace-nowrap text-base font-semibold text-gray-600 dark:text-gray-200"
|
||||
>
|
||||
{{
|
||||
baseStore.latest.block?.header?.chain_id || chainStore.chainName || ''
|
||||
#{{
|
||||
baseStore.latest?.block?.header?.height || chainStore.chainName || ''
|
||||
}}
|
||||
</div>
|
||||
<div
|
||||
|
@ -31,5 +31,5 @@ app.use(LazyLoad, { component: true });
|
||||
app.mount('#app');
|
||||
|
||||
// fetch latest block every 6s
|
||||
// const blockStore = useBaseStore()
|
||||
// setInterval(() => {blockStore.fetchLatest()}, 6000)
|
||||
const blockStore = useBaseStore()
|
||||
setInterval(() => {blockStore.fetchLatest()}, 6000)
|
||||
|
@ -5,19 +5,23 @@ import { useBlockModule } from './block';
|
||||
import DynamicComponent from '@/components/dynamic/DynamicComponent.vue';
|
||||
import { computed } from '@vue/reactivity';
|
||||
import { onBeforeRouteUpdate } from 'vue-router';
|
||||
import { useBaseStore } from '@/stores';
|
||||
import { ref } from 'vue';
|
||||
import type { Block } from '@/types';
|
||||
const props = defineProps(['height', 'chain']);
|
||||
|
||||
const store = useBlockModule();
|
||||
store.fetchBlock(props.height);
|
||||
const store = useBaseStore();
|
||||
const tab = ref('summary');
|
||||
const current = ref({} as Block)
|
||||
store.fetchBlock(props.height).then(x => current.value = x)
|
||||
|
||||
const height = computed(() => {
|
||||
return Number(store.current.block?.header?.height || props.height || 0);
|
||||
return Number(current.value.block?.header?.height || props.height || 0);
|
||||
});
|
||||
|
||||
onBeforeRouteUpdate(async (to, from, next) => {
|
||||
if (from.path !== to.path) {
|
||||
store.fetchBlock(String(to.params.height));
|
||||
store.fetchBlock(String(to.params.height)).then(x => current.value = x);
|
||||
next();
|
||||
}
|
||||
});
|
||||
@ -26,7 +30,7 @@ onBeforeRouteUpdate(async (to, from, next) => {
|
||||
<div>
|
||||
<div class="bg-base-100 px-4 pt-3 pb-4 rounded mb-4 shadow">
|
||||
<h2 class="card-title flex flex-row justify-between">
|
||||
<p class="">#{{ store.current.block?.header?.height }}</p>
|
||||
<p class="">#{{ current.block?.header?.height }}</p>
|
||||
<div class="" v-if="props.height">
|
||||
<RouterLink
|
||||
:to="`/${store.blockchain.chainName}/block/${height - 1}`"
|
||||
@ -43,23 +47,23 @@ onBeforeRouteUpdate(async (to, from, next) => {
|
||||
</div>
|
||||
</h2>
|
||||
<div>
|
||||
<DynamicComponent :value="store.current.block_id" />
|
||||
<DynamicComponent :value="current.block_id" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-base-100 px-4 pt-3 pb-4 rounded mb-4 shadow">
|
||||
<h2 class="card-title flex flex-row justify-between">Block Header</h2>
|
||||
<DynamicComponent :value="store.current.block?.header" />
|
||||
<DynamicComponent :value="current.block?.header" />
|
||||
</div>
|
||||
|
||||
<div class="bg-base-100 px-4 pt-3 pb-4 rounded mb-4 shadow">
|
||||
<h2 class="card-title flex flex-row justify-between">Transactions</h2>
|
||||
<TxsElement :value="store.current.block?.data?.txs" />
|
||||
<TxsElement :value="current.block?.data?.txs" />
|
||||
</div>
|
||||
|
||||
<div class="bg-base-100 px-4 pt-3 pb-4 rounded shadow">
|
||||
<h2 class="card-title flex flex-row justify-between">Last Commit</h2>
|
||||
<DynamicComponent :value="store.current.block?.last_commit" />
|
||||
<DynamicComponent :value="current.block?.last_commit" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -1,13 +1,12 @@
|
||||
<script lang="ts" setup>
|
||||
import { useBlockModule } from './block';
|
||||
import { computed, ref } from '@vue/reactivity';
|
||||
import { useFormatter } from '@/stores';
|
||||
import { useBaseStore, useFormatter } from '@/stores';
|
||||
const props = defineProps(['height', 'chain']);
|
||||
|
||||
const store = useBlockModule();
|
||||
// store.fetchBlock(props.height)
|
||||
const tab = ref('blocks');
|
||||
|
||||
const base = useBaseStore()
|
||||
|
||||
const format = useFormatter();
|
||||
</script>
|
||||
<template>
|
||||
@ -38,8 +37,8 @@ const format = useFormatter();
|
||||
<th>Time</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody v-if="store.recents && store.recents.length > 0" >
|
||||
<tr v-for="(item, index) in store.recents" :key="index">
|
||||
<tbody v-if="base.recents && base.recents.length > 0" >
|
||||
<tr v-for="(item, index) in base.recents" :key="index">
|
||||
<td class="text-sm text-primary">
|
||||
<RouterLink
|
||||
:to="`/${props.chain}/block/${item.block?.header?.height}`"
|
||||
@ -64,19 +63,21 @@ const format = useFormatter();
|
||||
<table class="table w-full">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="position: relative">Height</th>
|
||||
<th style="position: relative">Hash</th>
|
||||
<th>Messages</th>
|
||||
<th>Fees</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody v-if="store.txsInRecents && store.txsInRecents.length > 0" >
|
||||
<tr v-for="(item,index) in store.txsInRecents" :index="index">
|
||||
<td>
|
||||
<tbody >
|
||||
<tr v-for="(item,index) in base.txsInRecents" :index="index">
|
||||
<td>{{ item.height }}</td>
|
||||
<td class="text-xs truncate" width="50%">
|
||||
<RouterLink :to="`/${props.chain}/tx/${item.hash}`">{{
|
||||
item.hash
|
||||
}}</RouterLink>
|
||||
</td>
|
||||
<td>{{ format.messages(item.tx.body.messages as any) }}</td>
|
||||
<td>{{ format.messages(item.tx.body.messages) }}</td>
|
||||
<td>{{ format.formatTokens(item.tx.authInfo.fee?.amount) }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
@ -258,13 +258,10 @@ const color = computed(() => {
|
||||
<div class="text-lg font-semibold text-main">
|
||||
{{ format.formatToken(walletStore.balanceOfStakingToken) }}
|
||||
</div>
|
||||
<div class="text-sm">
|
||||
<span :class="color"
|
||||
>{{ format.showChanges(change) }}<small>%</small>
|
||||
<div class="text-sm" :class="color">
|
||||
<span class="ml-1">
|
||||
${{ format.tokenValue(walletStore.balanceOfStakingToken) }}
|
||||
</span>
|
||||
<span class="ml-1">{{
|
||||
format.tokenValue(walletStore.balanceOfStakingToken)
|
||||
}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-gray-100 dark:bg-[#373f59] rounded-sm px-4 py-3">
|
||||
@ -272,8 +269,8 @@ const color = computed(() => {
|
||||
<div class="text-lg font-semibold text-main">
|
||||
{{ format.formatToken(walletStore.stakingAmount) }}
|
||||
</div>
|
||||
<div class="text-sm">
|
||||
{{ format.tokenValue(walletStore.stakingAmount) }}
|
||||
<div class="text-sm" :class="color">
|
||||
${{ format.tokenValue(walletStore.stakingAmount) }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-gray-100 dark:bg-[#373f59] rounded-sm px-4 py-3">
|
||||
@ -281,8 +278,8 @@ const color = computed(() => {
|
||||
<div class="text-lg font-semibold text-main">
|
||||
{{ format.formatToken(walletStore.rewardAmount) }}
|
||||
</div>
|
||||
<div class="text-sm">
|
||||
{{ format.tokenValue(walletStore.rewardAmount) }}
|
||||
<div class="text-sm" :class="color">
|
||||
${{ format.tokenValue(walletStore.rewardAmount) }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-gray-100 dark:bg-[#373f59] rounded-sm px-4 py-3">
|
||||
@ -290,8 +287,8 @@ const color = computed(() => {
|
||||
<div class="text-lg font-semibold text-main">
|
||||
{{ format.formatToken(walletStore.unbondingAmount) }}
|
||||
</div>
|
||||
<div class="text-sm">
|
||||
{{ format.tokenValue(walletStore.unbondingAmount) }}
|
||||
<div class="text-sm" :class="color">
|
||||
${{ format.tokenValue(walletStore.unbondingAmount) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -82,7 +82,7 @@ const change24 = (key: Key) => {
|
||||
const change24Text = (key?: Key) => {
|
||||
if (!key) return '';
|
||||
const v = change24(key);
|
||||
return v !== 0 ? format.showChanges(v) : '';
|
||||
return v && v !== 0 ? format.showChanges(v) : '';
|
||||
};
|
||||
|
||||
const change24Color = (key?: Key) => {
|
||||
@ -202,7 +202,7 @@ const rank = function (position: number) {
|
||||
<th scope="col" class="text-right">VOTING POWER</th>
|
||||
<th scope="col" class="text-right">24h CHANGES</th>
|
||||
<th scope="col" class="text-right">COMMISSION</th>
|
||||
<th scope="col">ACTIONS</th>
|
||||
<th scope="col" class="text-center">ACTIONS</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@ -298,18 +298,9 @@ const rank = function (position: number) {
|
||||
:class="change24Color(v.consensus_pubkey)"
|
||||
>
|
||||
{{ change24Text(v.consensus_pubkey) }}
|
||||
<div
|
||||
v-if="v.jailed"
|
||||
class="text-xs truncate relative py-2 px-4 rounded-full w-fit text-error"
|
||||
>
|
||||
<span
|
||||
class="inset-x-0 inset-y-0 opacity-10 absolute bg-error"
|
||||
></span>
|
||||
Jailed
|
||||
</div>
|
||||
</td>
|
||||
<!-- 👉 commission -->
|
||||
<td class="text-right">
|
||||
<td class="text-right text-xs">
|
||||
{{
|
||||
format.formatCommissionRate(
|
||||
v.commission?.commission_rates?.rate
|
||||
@ -317,8 +308,12 @@ const rank = function (position: number) {
|
||||
}}
|
||||
</td>
|
||||
<!-- 👉 Action -->
|
||||
<td>
|
||||
<td class="text-center">
|
||||
<div v-if="v.jailed" class="badge badge-error gap-2 text-white">
|
||||
Jailed
|
||||
</div>
|
||||
<label
|
||||
v-else
|
||||
for="delegate"
|
||||
class="btn btn-xs bg-primary"
|
||||
@click="
|
||||
@ -326,8 +321,8 @@ const rank = function (position: number) {
|
||||
validator_address: v.operator_address,
|
||||
})
|
||||
"
|
||||
>Delegate</label
|
||||
>
|
||||
>Delegate</label>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
@ -1,7 +1,10 @@
|
||||
import { defineStore } from 'pinia';
|
||||
import { useBlockchain } from '@/stores';
|
||||
import { decodeTxRaw, type DecodedTxRaw } from '@cosmjs/proto-signing';
|
||||
import dayjs from 'dayjs';
|
||||
import type { Block } from '@/types';
|
||||
import { hashTx } from '@/libs';
|
||||
import { fromBase64 } from '@cosmjs/encoding';
|
||||
|
||||
export const useBaseStore = defineStore('baseStore', {
|
||||
state: () => {
|
||||
@ -29,6 +32,26 @@ export const useBaseStore = defineStore('baseStore', {
|
||||
blockchain() {
|
||||
return useBlockchain();
|
||||
},
|
||||
txsInRecents() {
|
||||
const txs = [] as { height: string, hash: string; tx: DecodedTxRaw }[];
|
||||
this.recents.forEach((b) =>
|
||||
b.block?.data?.txs.forEach((tx: string) => {
|
||||
if (tx) {
|
||||
const raw = fromBase64(tx)
|
||||
try {
|
||||
txs.push({
|
||||
height: b.block.header.height,
|
||||
hash: hashTx(raw),
|
||||
tx: decodeTxRaw(raw),
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
}
|
||||
})
|
||||
);
|
||||
return txs;
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
async initial() {
|
||||
@ -48,10 +71,13 @@ export const useBaseStore = defineStore('baseStore', {
|
||||
this.earlest = this.latest;
|
||||
this.recents = [];
|
||||
}
|
||||
if (this.recents.length >= 50) {
|
||||
this.recents.pop();
|
||||
//check if the block exists in recents
|
||||
if(this.recents.findIndex(x => x.block_id.hash === this.latest.block_id.hash) === -1 ) {
|
||||
if (this.recents.length >= 50) {
|
||||
this.recents.pop();
|
||||
}
|
||||
this.recents.push(this.latest);
|
||||
}
|
||||
this.recents.push(this.latest);
|
||||
return this.latest;
|
||||
},
|
||||
|
||||
@ -61,7 +87,7 @@ export const useBaseStore = defineStore('baseStore', {
|
||||
async fetchLatestValidators(offset = 0) {
|
||||
return this.blockchain.rpc.getBaseValidatorsetLatest(offset);
|
||||
},
|
||||
async fetchBlock(height?: number) {
|
||||
async fetchBlock(height?: number|string) {
|
||||
return this.blockchain.rpc.getBaseBlockAt(String(height));
|
||||
},
|
||||
async fetchAbciInfo() {
|
||||
|
@ -211,12 +211,13 @@ export const useFormatter = defineStore('formatter', {
|
||||
}
|
||||
return dayjs(time).format('YYYY-MM-DD HH:mm:ss');
|
||||
},
|
||||
messages(msgs: { '@type': string }[]) {
|
||||
messages(msgs: { '@type'?: string, typeUrl?: string }[]) {
|
||||
if (msgs) {
|
||||
const sum: Record<string, number> = msgs
|
||||
.map((msg) => {
|
||||
return msg['@type']
|
||||
.substring(msg['@type'].lastIndexOf('.') + 1)
|
||||
const msgType = msg['@type'] || msg.typeUrl || 'unknown'
|
||||
return msgType
|
||||
.substring(msgType.lastIndexOf('.') + 1)
|
||||
.replace('Msg', '');
|
||||
})
|
||||
.reduce((s, c) => {
|
||||
|
Loading…
Reference in New Issue
Block a user