atomatically load latest

This commit is contained in:
liangping 2023-05-14 09:23:18 +08:00
parent e7a21a9db9
commit eb79884c07
8 changed files with 81 additions and 57 deletions

View File

@ -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

View File

@ -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)

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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() {

View File

@ -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) => {