Merge pull request #380 from alisaweb3/v3-single
Timeline, Wallet Drapdown,Validator Detail,Governance Progress
This commit is contained in:
commit
b7dfc04f5e
@ -30,6 +30,38 @@ const veto = computed(() =>
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="grid grid-cols-4 gap-4 mb-3 text-sm">
|
||||
<div class="flex items-center justify-between rounded-sm px-2 relative">
|
||||
<div
|
||||
class="bg-yes absolute top-0 bottom-0 left-0 right-0 rounded-sm opacity-20 dark:opacity-40"
|
||||
></div>
|
||||
<div>YES</div>
|
||||
<div class="text-gray-800 dark:text-gray-50">{{ yes }}</div>
|
||||
</div>
|
||||
<div class="flex items-center justify-between rounded-sm px-2 relative">
|
||||
<div
|
||||
class="bg-no absolute top-0 bottom-0 left-0 right-0 rounded-sm opacity-20 dark:opacity-40"
|
||||
></div>
|
||||
<div>NO</div>
|
||||
<div class="text-gray-800 dark:text-gray-50">{{ no }}</div>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-between rounded-sm px-2 relative">
|
||||
<div
|
||||
class="bg-warning absolute top-0 bottom-0 left-0 right-0 rounded-sm opacity-20 dark:opacity-50"
|
||||
></div>
|
||||
<div>No With Veto</div>
|
||||
<div class="text-gray-800 dark:text-gray-50">{{ veto }}</div>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-between rounded-sm px-2 relative">
|
||||
<div
|
||||
class="bg-gray-500 absolute top-0 bottom-0 left-0 right-0 rounded-sm opacity-20 dark:opacity-40"
|
||||
></div>
|
||||
<div>Abstain</div>
|
||||
<div class="text-gray-800 dark:text-gray-50">{{ abstain }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="progress rounded-full h-1 text-xs flex items-center">
|
||||
<div class="h-1 bg-yes" :style="`width: ${yes}`"></div>
|
||||
<div class="h-1 bg-no" :style="`width: ${no}`"></div>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import VueApexCharts from 'vue3-apexcharts';
|
||||
import ApexCharts from 'vue3-apexcharts';
|
||||
import { useTheme } from 'vuetify';
|
||||
import { hexToRgb } from '@/plugins/vuetify/@layouts/utils';
|
||||
import { computed, type PropType } from 'vue';
|
||||
@ -141,7 +141,7 @@ const chartConfig = computed(() => {
|
||||
<div class="text-sm text-gray-500 dark:text-gray-400">
|
||||
{{ `Updated at ${format.toDay(props.commission?.update_time, 'short')}` }}
|
||||
</div>
|
||||
<VueApexCharts type="donut" :options="chartConfig" :series="series" />
|
||||
<ApexCharts type="donut" :options="chartConfig" :series="series" />
|
||||
<div>
|
||||
<div class="flex items-center justify-center flex-wrap gap-x-3">
|
||||
<div class="flex items-center gap-x-2">
|
||||
|
@ -1,5 +1,5 @@
|
||||
<script lang="ts" setup>
|
||||
import VueApexCharts from 'vue3-apexcharts';
|
||||
import ApexCharts from 'vue3-apexcharts';
|
||||
import { useTheme } from 'vuetify';
|
||||
import { getDonutChartConfig } from './apexChartConfig';
|
||||
|
||||
@ -13,7 +13,7 @@ const expenseRationChartConfig = computed(() =>
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<VueApexCharts
|
||||
<ApexCharts
|
||||
type="donut"
|
||||
height="410"
|
||||
:options="expenseRationChartConfig"
|
||||
|
@ -1,17 +1,14 @@
|
||||
<script lang="ts" setup>
|
||||
import VueApexCharts from 'vue3-apexcharts';
|
||||
import ApexCharts from 'vue3-apexcharts';
|
||||
import { useTheme } from 'vuetify';
|
||||
import {
|
||||
getAreaChartSplineConfig,
|
||||
getMarketPriceChartConfig,
|
||||
} from './apexChartConfig';
|
||||
import { getMarketPriceChartConfig } from './apexChartConfig';
|
||||
import { useIndexModule } from '@/modules/[chain]/indexStore';
|
||||
import { computed, ref } from '@vue/reactivity';
|
||||
|
||||
const store = useIndexModule();
|
||||
const vuetifyTheme = useTheme();
|
||||
const chartConfig = computed(() => {
|
||||
const labels = store.marketData.prices.map((x) => x[0]);
|
||||
const labels = store.marketData.prices.map((item: any) => item[0]);
|
||||
return getMarketPriceChartConfig(vuetifyTheme.current.value, labels);
|
||||
});
|
||||
const kind = ref('price');
|
||||
@ -21,8 +18,8 @@ const series = computed(() => {
|
||||
name: 'Price',
|
||||
data:
|
||||
kind.value === 'price'
|
||||
? store.marketData.prices.map((x) => x[1])
|
||||
: store.marketData.total_volumes.map((x) => x[1]),
|
||||
? store.marketData.prices.map((item: any) => item[1])
|
||||
: store.marketData.total_volumes.map((item: any) => item[1]),
|
||||
},
|
||||
];
|
||||
});
|
||||
@ -49,7 +46,7 @@ function changeChart(type: string) {
|
||||
Volume
|
||||
</a>
|
||||
</div>
|
||||
<VueApexCharts
|
||||
<ApexCharts
|
||||
type="area"
|
||||
height="230"
|
||||
:options="chartConfig"
|
||||
|
@ -25,7 +25,7 @@ const chain = useBlockchain();
|
||||
<table class="table w-full" density="compact" v-if="txs.length > 0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="position: relative">Hash</th>
|
||||
<th style="position: relative; z-index: 2;">Hash</th>
|
||||
<th>Msgs</th>
|
||||
<th>Memo</th>
|
||||
</tr>
|
||||
|
@ -21,10 +21,10 @@ const items = computed(() => [
|
||||
<template>
|
||||
<div class="d-flex flex-rows align-center">
|
||||
<span class="text-h5 mr-3">{{ moduleName }}</span>
|
||||
<Icon icon="mdi-dots-vertical"/>
|
||||
<Icon icon="mdi-dots-vertical" />
|
||||
<VBreadcrumbs :items="items">
|
||||
<template v-slot:divider>
|
||||
<Icon icon="mdi-chevron-right"/>
|
||||
<Icon icon="mdi-chevron-right" />
|
||||
</template>
|
||||
</VBreadcrumbs>
|
||||
</div>
|
||||
|
@ -11,7 +11,6 @@ import UserProfile from '@/layouts/components/ChainProfile.vue';
|
||||
import { useDashboard } from '@/stores/useDashboard';
|
||||
|
||||
import NavBarI18n from './NavBarI18n.vue';
|
||||
import NavBarNotifications from './NavBarNotifications.vue';
|
||||
import NavBarWallet from './NavBarWallet.vue';
|
||||
import { useBlockchain } from '@/stores';
|
||||
|
||||
@ -28,6 +27,13 @@ blockchain.$subscribe((m, s) => {
|
||||
});
|
||||
|
||||
const sidebarShow = ref(false);
|
||||
const sidebarOpen = ref(true);
|
||||
|
||||
const changeOpen = (index: Number) => {
|
||||
if (index === 0) {
|
||||
sidebarOpen.value = !sidebarOpen.value;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@ -49,10 +55,19 @@ const sidebarShow = ref(false);
|
||||
<div v-for="(item, index) of blockchain.computedChainMenu" :key="index">
|
||||
<div
|
||||
v-if="item?.title && item?.children?.length"
|
||||
:tabindex="index"
|
||||
class="collapse"
|
||||
:class="{ 'collapse-arrow': item?.children?.length > 0 }"
|
||||
:class="{
|
||||
'collapse-arrow': item?.children?.length > 0,
|
||||
'collapse-open': index === 0 && sidebarOpen,
|
||||
'collapse-close': index === 0 && !sidebarOpen,
|
||||
}"
|
||||
>
|
||||
<input type="checkbox" />
|
||||
<input
|
||||
type="checkbox"
|
||||
class="cursor-pointer"
|
||||
@click="changeOpen(index)"
|
||||
/>
|
||||
<div
|
||||
class="collapse-title px-4 flex items-center py-2 hover:bg-gray-100 dark:hover:bg-[#373f59]"
|
||||
>
|
||||
@ -175,7 +190,11 @@ const sidebarShow = ref(false);
|
||||
<NavBarI18n class="hidden md:inline-block" />
|
||||
<NavbarThemeSwitcher class="hidden md:inline-block" />
|
||||
|
||||
<NavBarWallet class="block truncate md:inline-block text-xs md:text-sm" />
|
||||
<NavBarWallet
|
||||
class="block truncate md:inline-block text-xs md:text-sm"
|
||||
/>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<!-- 👉 Pages -->
|
||||
|
@ -8,30 +8,37 @@ walletStore.$subscribe((m, s) => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<div v-if="walletStore.currentAddress"
|
||||
class="dropdown dropdown-hover ping-connect-dropdown"
|
||||
>
|
||||
<label tabindex="3" class="btn m-1" >{{ walletStore.shortAddress }}</label>
|
||||
<ul
|
||||
tabindex="3"
|
||||
class="dropdown-content menu p-2 shadow bg-base-100 rounded-box w-52"
|
||||
>
|
||||
<li>
|
||||
<a>{{ walletStore.connectedWallet }}</a>
|
||||
</li>
|
||||
<li>
|
||||
<a>{{ walletStore.currentAddress }}</a>
|
||||
</li>
|
||||
<div class="divider"></div>
|
||||
<li><a @click="walletStore.disconnect()">Disconnected</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<label
|
||||
v-else
|
||||
for="PingConnectWallet"
|
||||
class="btn btn-sm ml-4 ping-connect-btn"
|
||||
>Connect Wallet</label
|
||||
<div
|
||||
v-show="walletStore.currentAddress"
|
||||
class="dropdown dropdown-hover dropdown-end"
|
||||
>
|
||||
<label tabindex="0" class="btn btn-sm m-1 lowercase">{{ walletStore.shortAddress }}</label>
|
||||
<div
|
||||
tabindex="0"
|
||||
class="dropdown-content menu shadow p-2 bg-base-100 rounded w-64 overflow-auto"
|
||||
>
|
||||
<div class="px-2 mb-1 text-gray-500 dark:text-gray-400 font-semibold">
|
||||
{{ walletStore.connectedWallet?.wallet }}
|
||||
</div>
|
||||
<div class="">
|
||||
<a
|
||||
class="block py-2 px-2 hover:bg-gray-100 dark:hover:bg-[#353f5a] rounded cursor-pointer"
|
||||
style="overflow-wrap: anywhere"
|
||||
>
|
||||
{{ walletStore.currentAddress }}
|
||||
</a>
|
||||
<a
|
||||
class="block py-2 px-2 hover:bg-gray-100 dark:hover:bg-[#353f5a] rounded cursor-pointer"
|
||||
@click="walletStore.disconnect()"
|
||||
>Disconnected</a
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<label
|
||||
v-if="!walletStore?.currentAddress"
|
||||
for="PingConnectWallet"
|
||||
class="btn btn-sm ml-4 ping-connect-btn"
|
||||
>Connect Wallet</label
|
||||
>
|
||||
</template>
|
||||
|
@ -37,7 +37,8 @@
|
||||
</template>
|
||||
|
||||
<style>
|
||||
.footer-modal .ping-connect-btn {
|
||||
.footer-modal .ping-connect-btn,
|
||||
.footer-modal .ping-connect-dropdown {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
|
@ -1,234 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import type { SearchHeader, SearchItem } from '@/@fake-db/types';
|
||||
import axios from 'axios';
|
||||
import { useThemeConfig } from '@core/composable/useThemeConfig';
|
||||
|
||||
interface Suggestion {
|
||||
icon: string;
|
||||
title: string;
|
||||
url: object;
|
||||
}
|
||||
const { appContentLayoutNav } = useThemeConfig();
|
||||
|
||||
interface SuggestionGroup {
|
||||
title: string;
|
||||
content: Suggestion[];
|
||||
}
|
||||
|
||||
defineOptions({
|
||||
inheritAttrs: false,
|
||||
});
|
||||
|
||||
// 👉 Is App Search Bar Visible
|
||||
const isAppSearchBarVisible = ref(false);
|
||||
|
||||
// 👉 Default suggestions
|
||||
const suggestionGroups: SuggestionGroup[] = [
|
||||
{
|
||||
title: 'Popular Searches',
|
||||
content: [
|
||||
{
|
||||
icon: 'mdi-chart-donut',
|
||||
title: 'Analytics',
|
||||
url: { name: 'dashboards-analytics' },
|
||||
},
|
||||
{
|
||||
icon: 'mdi-chart-bubble',
|
||||
title: 'CRM',
|
||||
url: { name: 'dashboards-crm' },
|
||||
},
|
||||
{
|
||||
icon: 'mdi-file-outline',
|
||||
title: 'Invoice List',
|
||||
url: { name: 'apps-invoice-list' },
|
||||
},
|
||||
{
|
||||
icon: 'mdi-account-group-outline',
|
||||
title: 'User List',
|
||||
url: { name: 'apps-user-list' },
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'Apps & Pages',
|
||||
content: [
|
||||
{
|
||||
icon: 'mdi-calendar',
|
||||
title: 'Calendar',
|
||||
url: { name: 'apps-calendar' },
|
||||
},
|
||||
{
|
||||
icon: 'mdi-file-plus-outline',
|
||||
title: 'Invoice Add',
|
||||
url: { name: 'apps-invoice-add' },
|
||||
},
|
||||
{
|
||||
icon: 'mdi-currency-usd',
|
||||
title: 'Pricing',
|
||||
url: { name: 'pages-pricing' },
|
||||
},
|
||||
{
|
||||
icon: 'mdi-account-cog-outline',
|
||||
title: 'Account Settings',
|
||||
url: { name: 'pages-account-settings-tab', params: { tab: 'account' } },
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'User Interface',
|
||||
content: [
|
||||
{
|
||||
icon: 'mdi-alpha-a-box-outline',
|
||||
title: 'Typography',
|
||||
url: { name: 'pages-typography' },
|
||||
},
|
||||
{ icon: 'mdi-tab', title: 'Tabs', url: { name: 'components-tabs' } },
|
||||
{
|
||||
icon: 'mdi-gesture-tap-button',
|
||||
title: 'Buttons',
|
||||
url: { name: 'components-button' },
|
||||
},
|
||||
{
|
||||
icon: 'mdi-keyboard-settings-outline',
|
||||
title: 'Statistics',
|
||||
url: { name: 'pages-cards-card-statistics' },
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'Popular Searches',
|
||||
content: [
|
||||
{
|
||||
icon: 'mdi-format-list-checkbox',
|
||||
title: 'Select',
|
||||
url: { name: 'forms-select' },
|
||||
},
|
||||
{
|
||||
icon: 'mdi-lastpass',
|
||||
title: 'Combobox',
|
||||
url: { name: 'forms-combobox' },
|
||||
},
|
||||
{
|
||||
icon: 'mdi-calendar-range-outline',
|
||||
title: 'Date & Time Picker',
|
||||
url: { name: 'forms-date-time-picker' },
|
||||
},
|
||||
{
|
||||
icon: 'mdi-hexagram-outline',
|
||||
title: 'Rating',
|
||||
url: { name: 'forms-rating' },
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
// 👉 No Data suggestion
|
||||
const noDataSuggestions: Suggestion[] = [
|
||||
{
|
||||
title: 'Analytics Dashboard',
|
||||
icon: 'mdi-cart-outline',
|
||||
url: { name: 'dashboards-analytics' },
|
||||
},
|
||||
{
|
||||
title: 'Account Settings',
|
||||
icon: 'mdi-account-outline',
|
||||
url: { name: 'pages-account-settings-tab', params: { tab: 'account' } },
|
||||
},
|
||||
{
|
||||
title: 'Pricing Page',
|
||||
icon: 'mdi-cash',
|
||||
url: { name: 'pages-pricing' },
|
||||
},
|
||||
];
|
||||
|
||||
const searchQuery = ref('');
|
||||
const searchResult = ref<(SearchItem | SearchHeader)[]>([]);
|
||||
const router = useRouter();
|
||||
|
||||
// 👉 fetch search result API
|
||||
watchEffect(() => {
|
||||
axios
|
||||
.get('/app-bar/search', {
|
||||
params: {
|
||||
q: searchQuery.value,
|
||||
},
|
||||
})
|
||||
.then((response) => {
|
||||
searchResult.value = response.data;
|
||||
});
|
||||
});
|
||||
|
||||
// 👉 redirect the selected page
|
||||
const redirectToSuggestedOrSearchedPage = (selected: Suggestion) => {
|
||||
router.push(selected.url);
|
||||
|
||||
isAppSearchBarVisible.value = false;
|
||||
searchQuery.value = '';
|
||||
};
|
||||
|
||||
const LazyAppBarSearch = defineAsyncComponent(
|
||||
() => import('@core/components/AppBarSearch.vue')
|
||||
);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="d-flex align-center cursor-pointer"
|
||||
v-bind="$attrs"
|
||||
@click="isAppSearchBarVisible = !isAppSearchBarVisible"
|
||||
>
|
||||
<!-- 👉 Search Trigger button -->
|
||||
<IconBtn>
|
||||
<VIcon icon="mdi-magnify" />
|
||||
</IconBtn>
|
||||
|
||||
<span
|
||||
v-if="appContentLayoutNav === 'vertical'"
|
||||
class="d-none d-md-flex align-center text-disabled"
|
||||
>
|
||||
<span class="me-3">Search</span>
|
||||
<span class="meta-key">⌘K</span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- 👉 App Bar Search -->
|
||||
<LazyAppBarSearch
|
||||
v-model:isDialogVisible="isAppSearchBarVisible"
|
||||
v-model:search-query="searchQuery"
|
||||
:search-results="searchResult"
|
||||
:suggestions="suggestionGroups"
|
||||
:no-data-suggestion="noDataSuggestions"
|
||||
@item-selected="redirectToSuggestedOrSearchedPage"
|
||||
>
|
||||
<!--
|
||||
<template #suggestions>
|
||||
use this slot if you want to override default suggestions
|
||||
</template>
|
||||
-->
|
||||
|
||||
<!--
|
||||
<template #noData>
|
||||
use this slot to change the view of no data section
|
||||
</template>
|
||||
-->
|
||||
|
||||
<!--
|
||||
<template #searchResult="{ item }">
|
||||
use this slot to change the search item
|
||||
</template>
|
||||
-->
|
||||
</LazyAppBarSearch>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@use '@styles/variables/_vuetify.scss';
|
||||
|
||||
.meta-key {
|
||||
border: thin solid rgba(var(--v-border-color), var(--v-border-opacity));
|
||||
border-radius: 6px;
|
||||
block-size: 1.5625rem;
|
||||
line-height: 1.3125rem;
|
||||
padding-block: 0.125rem;
|
||||
padding-inline: 0.25rem;
|
||||
}
|
||||
</style>
|
@ -93,7 +93,7 @@ loadAccount(props.address);
|
||||
<div v-if="account">
|
||||
<!-- address -->
|
||||
<div class="bg-base-100 px-4 pt-3 pb-4 rounded mb-4 shadow">
|
||||
<div class="d-flex items-center">
|
||||
<div class="flex items-center">
|
||||
<!-- img -->
|
||||
<div class="inline-flex relative w-11 h-11 rounded-md">
|
||||
<div
|
||||
@ -126,7 +126,7 @@ loadAccount(props.address);
|
||||
</div>
|
||||
<div class="mt-4 md:col-span-2 md:mt-0 md:ml-4">
|
||||
<!-- button -->
|
||||
<div class="d-flex justify-end mb-4">
|
||||
<div class="flex justify-end mb-4 pr-5">
|
||||
<label
|
||||
for="send"
|
||||
class="btn btn-primary btn-sm mr-2"
|
||||
@ -144,74 +144,105 @@ loadAccount(props.address);
|
||||
>transfer</label
|
||||
>
|
||||
</div>
|
||||
<!-- -->
|
||||
<!-- list-->
|
||||
<div class="">
|
||||
<VListItem v-for="v in balances">
|
||||
<template #prepend>
|
||||
<VAvatar rounded variant="tonal" size="35" color="info">
|
||||
<VIcon icon="mdi-account-cash" size="20" />
|
||||
</VAvatar>
|
||||
</template>
|
||||
<VListItemTitle class="text-sm font-weight-semibold">
|
||||
{{ format.formatToken(v) }}
|
||||
</VListItemTitle>
|
||||
<VListItemSubtitle class="text-xs"> ≈${{ 0 }} </VListItemSubtitle>
|
||||
<template #append>
|
||||
<!--balances -->
|
||||
<div
|
||||
class="flex items-center px-4 mb-2"
|
||||
v-for="(balanceItem, index) in balances"
|
||||
:key="index"
|
||||
>
|
||||
<div
|
||||
class="w-9 h-9 rounded overflow-hidden flex items-center justify-center relative mr-4"
|
||||
>
|
||||
<Icon icon="mdi-account-cash" class="text-info" size="20" />
|
||||
<div
|
||||
class="text-xs truncate relative py-2 px-4 rounded-full w-fit text-primary mr-2"
|
||||
>
|
||||
<span
|
||||
class="inset-x-0 inset-y-0 opacity-10 absolute bg-primary"
|
||||
></span>
|
||||
{{ format.calculatePercent(v.amount, totalAmount) }}
|
||||
class="absolute top-0 bottom-0 left-0 right-0 bg-info opacity-20"
|
||||
></div>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<div class="text-sm font-semibold">
|
||||
{{ format.formatToken(balanceItem) }}
|
||||
</div>
|
||||
</template>
|
||||
</VListItem>
|
||||
<VListItem v-for="v in delegations">
|
||||
<template #prepend>
|
||||
<VAvatar rounded variant="tonal" size="35" color="warning">
|
||||
<VIcon icon="mdi-user-clock" size="20" />
|
||||
</VAvatar>
|
||||
</template>
|
||||
|
||||
<VListItemTitle class="text-sm font-weight-semibold">
|
||||
{{ format.formatToken(v.balance) }}
|
||||
</VListItemTitle>
|
||||
<VListItemSubtitle class="text-xs"> ≈${{ 0 }} </VListItemSubtitle>
|
||||
<template #append>
|
||||
<div class="text-xs">≈${{ 0 }}</div>
|
||||
</div>
|
||||
<div
|
||||
class="text-xs truncate relative py-1 px-3 rounded-full w-fit text-primary mr-2"
|
||||
>
|
||||
<span
|
||||
class="inset-x-0 inset-y-0 opacity-10 absolute bg-primary text-sm"
|
||||
></span>
|
||||
{{ format.calculatePercent(balanceItem.amount, totalAmount) }}
|
||||
</div>
|
||||
</div>
|
||||
<!--delegations -->
|
||||
<div
|
||||
class="flex items-center px-4 mb-2"
|
||||
v-for="(delegationItem, index) in delegations"
|
||||
:key="index"
|
||||
>
|
||||
<div
|
||||
class="w-9 h-9 rounded overflow-hidden flex items-center justify-center relative mr-4"
|
||||
>
|
||||
<Icon icon="mdi-user-clock" class="text-warning" size="20" />
|
||||
<div
|
||||
class="text-xs truncate relative py-2 px-4 rounded-full w-fit text-primary mr-2"
|
||||
>
|
||||
<span
|
||||
class="inset-x-0 inset-y-0 opacity-10 absolute bg-primary"
|
||||
></span>
|
||||
{{ format.calculatePercent(v.balance.amount, totalAmount) }}
|
||||
class="absolute top-0 bottom-0 left-0 right-0 bg-warning opacity-20"
|
||||
></div>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<div class="text-sm font-semibold">
|
||||
{{ format.formatToken(delegationItem?.balance) }}
|
||||
</div>
|
||||
</template>
|
||||
</VListItem>
|
||||
<VListItem v-for="v in rewards.total">
|
||||
<template #prepend>
|
||||
<VAvatar rounded variant="tonal" size="35" color="success">
|
||||
<VIcon icon="mdi-account-arrow-up" size="20" />
|
||||
</VAvatar>
|
||||
</template>
|
||||
|
||||
<VListItemTitle class="text-sm font-weight-semibold">
|
||||
{{ format.formatToken(v) }}
|
||||
</VListItemTitle>
|
||||
<VListItemSubtitle class="text-xs"> ≈${{ 0 }} </VListItemSubtitle>
|
||||
<template #append>
|
||||
<div class="text-xs">≈${{ 0 }}</div>
|
||||
</div>
|
||||
<div
|
||||
class="text-xs truncate relative py-1 px-3 rounded-full w-fit text-primary mr-2"
|
||||
>
|
||||
<span
|
||||
class="inset-x-0 inset-y-0 opacity-10 absolute bg-primary text-sm"
|
||||
></span>
|
||||
{{
|
||||
format.calculatePercent(
|
||||
delegationItem?.balance?.amount,
|
||||
totalAmount
|
||||
)
|
||||
}}
|
||||
</div>
|
||||
</div>
|
||||
<!-- rewards.total -->
|
||||
<div
|
||||
class="flex items-center px-4 mb-2"
|
||||
v-for="(rewardItem, index) in rewards.total"
|
||||
:key="index"
|
||||
>
|
||||
<div
|
||||
class="w-9 h-9 rounded overflow-hidden flex items-center justify-center relative mr-4"
|
||||
>
|
||||
<Icon
|
||||
icon="mdi-account-arrow-up"
|
||||
class="text-success"
|
||||
size="20"
|
||||
/>
|
||||
<div
|
||||
class="text-xs truncate relative py-2 px-4 rounded-full w-fit text-primary mr-2"
|
||||
>
|
||||
<span
|
||||
class="inset-x-0 inset-y-0 opacity-10 absolute bg-primary"
|
||||
></span>
|
||||
{{ format.calculatePercent(v.amount, totalAmount) }}
|
||||
class="absolute top-0 bottom-0 left-0 right-0 bg-success opacity-20"
|
||||
></div>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<div class="text-sm font-semibold">
|
||||
{{ format.formatToken(rewardItem) }}
|
||||
</div>
|
||||
</template>
|
||||
</VListItem>
|
||||
|
||||
<div class="text-xs">≈${{ 0 }}</div>
|
||||
</div>
|
||||
<div
|
||||
class="text-xs truncate relative py-1 px-3 rounded-full w-fit text-primary mr-2"
|
||||
>
|
||||
<span
|
||||
class="inset-x-0 inset-y-0 opacity-10 absolute bg-primary text-sm"
|
||||
></span>
|
||||
{{ format.calculatePercent(rewardItem.amount, totalAmount) }}
|
||||
</div>
|
||||
</div>
|
||||
<!-- mdi-account-arrow-right -->
|
||||
<div class="flex items-center px-4">
|
||||
<div
|
||||
class="w-9 h-9 rounded overflow-hidden flex items-center justify-center relative mr-4"
|
||||
@ -225,9 +256,8 @@ loadAccount(props.address);
|
||||
class="absolute top-0 bottom-0 left-0 right-0 bg-error opacity-20"
|
||||
></div>
|
||||
</div>
|
||||
|
||||
<div class="flex-1">
|
||||
<div class="text-base font-semibold">
|
||||
<div class="text-sm font-semibold">
|
||||
{{
|
||||
format.formatToken({
|
||||
amount: String(unbondingTotal),
|
||||
@ -235,10 +265,10 @@ loadAccount(props.address);
|
||||
})
|
||||
}}
|
||||
</div>
|
||||
<div class="text-sm">≈${{ 0 }}</div>
|
||||
<div class="text-xs">≈${{ 0 }}</div>
|
||||
</div>
|
||||
<div
|
||||
class="text-xs truncate relative py-2 px-4 rounded-full w-fit text-primary mr-2"
|
||||
class="text-xs truncate relative py-1 px-3 rounded-full w-fit text-primary mr-2"
|
||||
>
|
||||
<span
|
||||
class="inset-x-0 inset-y-0 opacity-10 absolute bg-primary"
|
||||
@ -247,153 +277,17 @@ loadAccount(props.address);
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="divider"></div>
|
||||
{{ totalAmount }}
|
||||
<div class="mt-4 text-lg font-semibold mr-5 pl-5 border-t pt-4">
|
||||
{{ totalAmount }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<VCard class="mt-5">
|
||||
<VCardTitle>Assets</VCardTitle>
|
||||
<VCardItem>
|
||||
<VRow>
|
||||
<VCol cols="12" md="4">
|
||||
<DonutChart :series="totalAmountByCategory" :labels="labels" />
|
||||
</VCol>
|
||||
<VCol cols="12" md="8">
|
||||
<VList class="card-list">
|
||||
<VListItem>
|
||||
<label
|
||||
for="transfer"
|
||||
class="btn btn-primary float-right btn-sm"
|
||||
@click="
|
||||
dialog.open('transfer', {
|
||||
chain_name: blockchain.current?.prettyName,
|
||||
})
|
||||
"
|
||||
>transfer</label
|
||||
>
|
||||
<label
|
||||
for="send"
|
||||
class="btn btn-primary float-right btn-sm"
|
||||
@click="dialog.open('send', {})"
|
||||
>Send</label
|
||||
>
|
||||
</VListItem>
|
||||
<VListItem v-for="v in balances">
|
||||
<template #prepend>
|
||||
<VAvatar rounded variant="tonal" size="35" color="info">
|
||||
<VIcon icon="mdi-account-cash" size="20" />
|
||||
</VAvatar>
|
||||
</template>
|
||||
<VListItemTitle class="text-sm font-weight-semibold">
|
||||
{{ format.formatToken(v) }}
|
||||
</VListItemTitle>
|
||||
<VListItemSubtitle class="text-xs">
|
||||
≈${{ 0 }}
|
||||
</VListItemSubtitle>
|
||||
<template #append>
|
||||
<div
|
||||
class="text-xs truncate relative py-2 px-4 rounded-full w-fit text-primary mr-2"
|
||||
>
|
||||
<span
|
||||
class="inset-x-0 inset-y-0 opacity-10 absolute bg-primary"
|
||||
></span>
|
||||
{{ format.calculatePercent(v.amount, totalAmount) }}
|
||||
</div>
|
||||
</template>
|
||||
</VListItem>
|
||||
<VListItem v-for="v in delegations">
|
||||
<template #prepend>
|
||||
<VAvatar rounded variant="tonal" size="35" color="warning">
|
||||
<VIcon icon="mdi-user-clock" size="20" />
|
||||
</VAvatar>
|
||||
</template>
|
||||
|
||||
<VListItemTitle class="text-sm font-weight-semibold">
|
||||
{{ format.formatToken(v.balance) }}
|
||||
</VListItemTitle>
|
||||
<VListItemSubtitle class="text-xs">
|
||||
≈${{ 0 }}
|
||||
</VListItemSubtitle>
|
||||
<template #append>
|
||||
<div
|
||||
class="text-xs truncate relative py-2 px-4 rounded-full w-fit text-primary mr-2"
|
||||
>
|
||||
<span
|
||||
class="inset-x-0 inset-y-0 opacity-10 absolute bg-primary"
|
||||
></span>
|
||||
{{ format.calculatePercent(v.balance.amount, totalAmount) }}
|
||||
</div>
|
||||
</template>
|
||||
</VListItem>
|
||||
<VListItem v-for="v in rewards.total">
|
||||
<template #prepend>
|
||||
<VAvatar rounded variant="tonal" size="35" color="success">
|
||||
<VIcon icon="mdi-account-arrow-up" size="20" />
|
||||
</VAvatar>
|
||||
</template>
|
||||
|
||||
<VListItemTitle class="text-sm font-weight-semibold">
|
||||
{{ format.formatToken(v) }}
|
||||
</VListItemTitle>
|
||||
<VListItemSubtitle class="text-xs">
|
||||
≈${{ 0 }}
|
||||
</VListItemSubtitle>
|
||||
<template #append>
|
||||
<div
|
||||
class="text-xs truncate relative py-2 px-4 rounded-full w-fit text-primary mr-2"
|
||||
>
|
||||
<span
|
||||
class="inset-x-0 inset-y-0 opacity-10 absolute bg-primary"
|
||||
></span>
|
||||
{{ format.calculatePercent(v.amount, totalAmount) }}
|
||||
</div>
|
||||
</template>
|
||||
</VListItem>
|
||||
|
||||
<VListItem>
|
||||
<template #prepend>
|
||||
<VAvatar rounded variant="tonal" size="35" color="error">
|
||||
<VIcon icon="mdi-account-arrow-right" size="20" />
|
||||
</VAvatar>
|
||||
</template>
|
||||
|
||||
<VListItemTitle class="text-sm font-weight-semibold">
|
||||
{{
|
||||
format.formatToken({
|
||||
amount: String(unbondingTotal),
|
||||
denom: stakingStore.params.bond_denom,
|
||||
})
|
||||
}}
|
||||
</VListItemTitle>
|
||||
<VListItemSubtitle class="text-xs">
|
||||
≈${{ 0 }}
|
||||
</VListItemSubtitle>
|
||||
<template #append>
|
||||
<div
|
||||
class="text-xs truncate relative py-2 px-4 rounded-full w-fit text-primary mr-2"
|
||||
>
|
||||
<span
|
||||
class="inset-x-0 inset-y-0 opacity-10 absolute bg-primary"
|
||||
></span>
|
||||
{{ format.calculatePercent(unbondingTotal, totalAmount) }}
|
||||
</div>
|
||||
</template>
|
||||
</VListItem>
|
||||
</VList>
|
||||
<VDivider class="my-2"></VDivider>
|
||||
{{ totalAmount }}
|
||||
</VCol>
|
||||
</VRow>
|
||||
</VCardItem>
|
||||
</VCard>
|
||||
|
||||
<!-- Delegations -->
|
||||
<div class="bg-base-100 px-4 pt-3 pb-4 rounded mb-4 shadow">
|
||||
<h2 class="card-title mb-4">Delegations</h2>
|
||||
<div class="d-flex justify-end mb-4">
|
||||
<div class="flex justify-end mb-4">
|
||||
<label
|
||||
for="delegate"
|
||||
class="btn btn-primary btn-sm mr-2"
|
||||
@ -408,18 +302,18 @@ loadAccount(props.address);
|
||||
>
|
||||
</div>
|
||||
<div class="overdflow-x-auto">
|
||||
<table class="table w-full">
|
||||
<table class="table w-full text-sm table-zebra">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="position: relative">Validator</th>
|
||||
<th>Delegation</th>
|
||||
<th>Rewards</th>
|
||||
<th>Action</th>
|
||||
<th class="py-3">Validator</th>
|
||||
<th class="py-3">Delegation</th>
|
||||
<th class="py-3">Rewards</th>
|
||||
<th class="py-3">Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="text-sm">
|
||||
<tr v-for="v in delegations">
|
||||
<td class="text-caption text-primary">
|
||||
<tr v-for="(v, index) in delegations" :key="index">
|
||||
<td class="text-caption text-primary py-3">
|
||||
<RouterLink
|
||||
:to="`/${chain}/staking/${v.delegation.validator_address}`"
|
||||
>{{
|
||||
@ -427,8 +321,10 @@ loadAccount(props.address);
|
||||
}}</RouterLink
|
||||
>
|
||||
</td>
|
||||
<td>{{ format.formatToken(v.balance, true, '0,0.[00]') }}</td>
|
||||
<td>
|
||||
<td class="py-3">
|
||||
{{ format.formatToken(v.balance, true, '0,0.[00]') }}
|
||||
</td>
|
||||
<td class="py-3">
|
||||
{{
|
||||
format.formatTokens(
|
||||
rewards?.rewards?.find(
|
||||
@ -438,11 +334,11 @@ loadAccount(props.address);
|
||||
)
|
||||
}}
|
||||
</td>
|
||||
<td>
|
||||
<div class="d-flex justify-end">
|
||||
<td class="py-3">
|
||||
<div class="flex justify-end">
|
||||
<label
|
||||
for="delegate"
|
||||
class="btn btn-primary btn-sm mr-2"
|
||||
class="btn btn-primary btn-xs mr-2"
|
||||
@click="
|
||||
dialog.open('delegate', {
|
||||
validator_address: v.delegation.validator_address,
|
||||
@ -452,7 +348,7 @@ loadAccount(props.address);
|
||||
>
|
||||
<label
|
||||
for="redelegate"
|
||||
class="btn btn-primary btn-sm mr-2"
|
||||
class="btn btn-primary btn-xs mr-2"
|
||||
@click="
|
||||
dialog.open('redelegate', {
|
||||
validator_address: v.delegation.validator_address,
|
||||
@ -462,7 +358,7 @@ loadAccount(props.address);
|
||||
>
|
||||
<label
|
||||
for="unbond"
|
||||
class="btn btn-primary btn-sm"
|
||||
class="btn btn-primary btn-xs"
|
||||
@click="
|
||||
dialog.open('unbond', {
|
||||
validator_address: v.delegation.validator_address,
|
||||
@ -485,19 +381,19 @@ loadAccount(props.address);
|
||||
>
|
||||
<h2 class="card-title mb-4">Unbonding Delegations</h2>
|
||||
<div class="overflow-x-auto">
|
||||
<table class="table">
|
||||
<table class="table text-sm w-full">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="position: relative">Creation Height</th>
|
||||
<th>Initial Balance</th>
|
||||
<th>Balance</th>
|
||||
<th>Completion Time</th>
|
||||
<th class="py-3">Creation Height</th>
|
||||
<th class="py-3">Initial Balance</th>
|
||||
<th class="py-3">Balance</th>
|
||||
<th class="py-3">Completion Time</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="text-sm">
|
||||
<div v-for="v in unbonding">
|
||||
<div v-for="(v, index) in unbonding" :key="index">
|
||||
<tr>
|
||||
<td class="text-caption text-primary">
|
||||
<td class="text-caption text-primary py-3">
|
||||
<RouterLink
|
||||
:to="`/${chain}/staking/${v.validator_address}`"
|
||||
>{{
|
||||
@ -507,8 +403,8 @@ loadAccount(props.address);
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-for="entry in v.entries">
|
||||
<td>{{ entry.creation_height }}</td>
|
||||
<td>
|
||||
<td class="py-3">{{ entry.creation_height }}</td>
|
||||
<td class="py-3">
|
||||
{{
|
||||
format.formatToken(
|
||||
{
|
||||
@ -520,7 +416,7 @@ loadAccount(props.address);
|
||||
)
|
||||
}}
|
||||
</td>
|
||||
<td>
|
||||
<td class="py-3">
|
||||
{{
|
||||
format.formatToken(
|
||||
{
|
||||
@ -532,7 +428,9 @@ loadAccount(props.address);
|
||||
)
|
||||
}}
|
||||
</td>
|
||||
<td>{{ format.toDay(entry.completion_time, 'to') }}</td>
|
||||
<td class="py-3">
|
||||
{{ format.toDay(entry.completion_time, 'to') }}
|
||||
</td>
|
||||
</tr>
|
||||
</div>
|
||||
</tbody>
|
||||
@ -544,35 +442,37 @@ loadAccount(props.address);
|
||||
<div class="bg-base-100 px-4 pt-3 pb-4 rounded mb-4 shadow">
|
||||
<h2 class="card-title mb-4">Transactions</h2>
|
||||
<div class="overflow-x-auto">
|
||||
<table class="table w-full">
|
||||
<table class="table w-full text-sm">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="position: relative">Height</th>
|
||||
<th>Hash</th>
|
||||
<th>Messages</th>
|
||||
<th>Time</th>
|
||||
<th class="py-3">Height</th>
|
||||
<th class="py-3">Hash</th>
|
||||
<th class="py-3">Messages</th>
|
||||
<th class="py-3">Time</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="text-sm">
|
||||
<tr v-for="v in txs">
|
||||
<td class="text-sm text-primary">
|
||||
<tr v-for="(v, index) in txs" :key="index">
|
||||
<td class="text-sm text-primary py-3">
|
||||
<RouterLink :to="`/${chain}/block/${v.height}`">{{
|
||||
v.height
|
||||
}}</RouterLink>
|
||||
</td>
|
||||
<td class="text-truncate" style="max-width: 200px">
|
||||
<td class="text-truncate py-3" style="max-width: 200px">
|
||||
{{ v.txhash }}
|
||||
</td>
|
||||
<td>
|
||||
{{ format.messages(v.tx.body.messages) }}
|
||||
<VIcon
|
||||
<td class="flex items-center py-3">
|
||||
<div class="mr-2">
|
||||
{{ format.messages(v.tx.body.messages) }}
|
||||
</div>
|
||||
<Icon
|
||||
v-if="v.code === 0"
|
||||
icon="mdi-check"
|
||||
color="success"
|
||||
></VIcon>
|
||||
<VIcon v-else icon="mdi-multiply" color="error"></VIcon>
|
||||
class="text-success text-lg"
|
||||
/>
|
||||
<Icon v-else icon="mdi-multiply" class="text-error text-lg" />
|
||||
</td>
|
||||
<td>{{ format.toDay(v.timestamp, 'from') }}</td>
|
||||
<td class="py-3">{{ format.toDay(v.timestamp, 'from') }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@ -585,10 +485,5 @@ loadAccount(props.address);
|
||||
<DynamicComponent :value="account" />
|
||||
</div>
|
||||
</div>
|
||||
<div v-else>Account does not exists on chain</div>
|
||||
<div v-else class="text-no text-sm">Account does not exists on chain</div>
|
||||
</template>
|
||||
<style lang="scss" scoped>
|
||||
.card-list {
|
||||
--v-card-list-gap: 5px;
|
||||
}
|
||||
</style>
|
||||
|
@ -55,13 +55,13 @@ export const useBlockModule = defineStore('blockModule', {
|
||||
});
|
||||
},
|
||||
async fetchLatest() {
|
||||
this.latest = await this.blockchain.rpc.getBaseBlockLatest();
|
||||
this.latest = await this.blockchain.rpc?.getBaseBlockLatest();
|
||||
if (this.recents.length >= 50) this.recents.shift();
|
||||
this.recents.push(this.latest);
|
||||
return this.latest;
|
||||
},
|
||||
async fetchBlock(height: string) {
|
||||
this.current = await this.blockchain.rpc.getBaseBlockAt(height);
|
||||
this.current = await this.blockchain.rpc?.getBaseBlockAt(height);
|
||||
return this.current;
|
||||
},
|
||||
},
|
||||
|
@ -30,7 +30,7 @@ const format = useFormatter();
|
||||
<table class="table w-full">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="position: relative">Height</th>
|
||||
<th style="position: relative; z-index: 2;">Height</th>
|
||||
<th>Hash</th>
|
||||
<th>Proposer</th>
|
||||
<th>Txs</th>
|
||||
@ -63,8 +63,8 @@ const format = useFormatter();
|
||||
<table class="table w-full">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="position: relative">Height</th>
|
||||
<th style="position: relative">Hash</th>
|
||||
<th style="position: relative; z-index: 2;">Height</th>
|
||||
<th style="position: relative; z-index: 2;">Hash</th>
|
||||
<th>Messages</th>
|
||||
<th>Fees</th>
|
||||
</tr>
|
||||
|
@ -29,7 +29,7 @@ const selected = ref('');
|
||||
function showInfo(address: string) {
|
||||
wasmStore.wasmClient.getWasmContracts(address).then((x) => {
|
||||
info.value = x.contract_info;
|
||||
infoDialog.value = true;
|
||||
// infoDialog.value = true;
|
||||
});
|
||||
}
|
||||
function showState(address: string) {
|
||||
@ -99,20 +99,21 @@ const result = ref('');
|
||||
<table class="table w-full mt-4">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="position: relative">Contract List</th>
|
||||
<th style="position: relative; z-index: 2">Contract List</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="v in response.contracts">
|
||||
<tr v-for="(v, index) in response.contracts" :key="index">
|
||||
<td>{{ v }}</td>
|
||||
<td>
|
||||
<button
|
||||
class="btn btn-primary btn-sm text-xs mr-2"
|
||||
<label
|
||||
@click="showInfo(v)"
|
||||
for="modal-contract-detail"
|
||||
class="btn btn-primary btn-sm text-xs mr-2"
|
||||
>contract</label
|
||||
>
|
||||
contract
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="btn btn-primary btn-sm text-xs mr-2"
|
||||
@click="showState(v)"
|
||||
@ -132,19 +133,25 @@ const result = ref('');
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<v-dialog v-model="infoDialog" width="auto">
|
||||
<v-card>
|
||||
<VCardTitle>Contract Detail</VCardTitle>
|
||||
<v-card-text>
|
||||
<DynamicComponent :value="info" />
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-btn color="primary" block @click="infoDialog = false"
|
||||
>Close Dialog</v-btn
|
||||
>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
<input type="checkbox" id="modal-contract-detail" class="modal-toggle" />
|
||||
<label for="modal-contract-detail" class="modal cursor-pointer">
|
||||
<label class="modal-box relative p-2" for="">
|
||||
<div>
|
||||
<div class="flex items-center justify-between px-3 pt-2">
|
||||
<div class="text-lg">Contract Detail</div>
|
||||
<label
|
||||
@click="infoDialog = false"
|
||||
for="modal-contract-detail"
|
||||
class="btn btn-sm btn-circle"
|
||||
>✕</label
|
||||
>
|
||||
</div>
|
||||
<div>
|
||||
<DynamicComponent :value="info" />
|
||||
</div>
|
||||
</div>
|
||||
</label>
|
||||
</label>
|
||||
|
||||
<v-dialog v-model="stateDialog" width="auto">
|
||||
<v-card>
|
||||
|
@ -20,7 +20,7 @@ wasmStore.wasmClient.getWasmCodeList().then((x) => {
|
||||
<table class="table w-full mt-4 text-sm">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="position: relative">Code Id</th>
|
||||
<th style="position: relative; z-index: 2;">Code Id</th>
|
||||
<th>Code Hash</th>
|
||||
<th>Creator</th>
|
||||
<th>Permissions</th>
|
||||
|
@ -1,318 +1,353 @@
|
||||
<script lang="ts" setup>
|
||||
import ObjectElement from '@/components/dynamic/ObjectElement.vue';
|
||||
import { useBaseStore, useFormatter, useGovStore, useStakingStore, useTxDialog } from '@/stores';
|
||||
import type { GovProposal, GovVote, PaginabledAccounts, PaginatedProposalDeposit, PaginatedProposalVotes, Pagination } from '@/types';
|
||||
import { ref , reactive} from 'vue';
|
||||
import {
|
||||
useBaseStore,
|
||||
useFormatter,
|
||||
useGovStore,
|
||||
useStakingStore,
|
||||
useTxDialog,
|
||||
} from '@/stores';
|
||||
import type {
|
||||
GovProposal,
|
||||
GovVote,
|
||||
PaginatedProposalDeposit,
|
||||
Pagination,
|
||||
} from '@/types';
|
||||
import { ref, reactive } from 'vue';
|
||||
import Countdown from '@/components/Countdown.vue';
|
||||
import { computed } from '@vue/reactivity';
|
||||
|
||||
const props = defineProps(["proposal_id", "chain"]);
|
||||
const proposal = ref({} as GovProposal)
|
||||
const format = useFormatter()
|
||||
const store = useGovStore()
|
||||
const dialog = useTxDialog()
|
||||
const props = defineProps(['proposal_id', 'chain']);
|
||||
const proposal = ref({} as GovProposal);
|
||||
const format = useFormatter();
|
||||
const store = useGovStore();
|
||||
const dialog = useTxDialog();
|
||||
|
||||
store.fetchProposal(props.proposal_id).then((res) => {
|
||||
const proposalDetail = reactive(res.proposal)
|
||||
// when status under the voting, final_tally_result are no data, should request fetchTally
|
||||
if (res.proposal?.status === 'PROPOSAL_STATUS_VOTING_PERIOD'){
|
||||
store.fetchTally(props.proposal_id).then((tallRes)=>{
|
||||
proposalDetail.final_tally_result = tallRes?.tally
|
||||
})
|
||||
}
|
||||
proposal.value = proposalDetail
|
||||
})
|
||||
const proposalDetail = reactive(res.proposal);
|
||||
// when status under the voting, final_tally_result are no data, should request fetchTally
|
||||
if (res.proposal?.status === 'PROPOSAL_STATUS_VOTING_PERIOD') {
|
||||
store.fetchTally(props.proposal_id).then((tallRes) => {
|
||||
proposalDetail.final_tally_result = tallRes?.tally;
|
||||
});
|
||||
}
|
||||
proposal.value = proposalDetail;
|
||||
});
|
||||
|
||||
const color = computed(() => {
|
||||
if (proposal.value.status==='PROPOSAL_STATUS_PASSED') {
|
||||
return "success"
|
||||
}else if (proposal.value.status==='PROPOSAL_STATUS_REJECTED') {
|
||||
return "error"
|
||||
}
|
||||
return ""
|
||||
})
|
||||
if (proposal.value.status === 'PROPOSAL_STATUS_PASSED') {
|
||||
return 'success';
|
||||
} else if (proposal.value.status === 'PROPOSAL_STATUS_REJECTED') {
|
||||
return 'error';
|
||||
}
|
||||
return '';
|
||||
});
|
||||
const status = computed(() => {
|
||||
if(proposal.value.status) {
|
||||
return proposal.value.status.replace("PROPOSAL_STATUS_", "")
|
||||
}
|
||||
return ""
|
||||
})
|
||||
if (proposal.value.status) {
|
||||
return proposal.value.status.replace('PROPOSAL_STATUS_', '');
|
||||
}
|
||||
return '';
|
||||
});
|
||||
|
||||
const deposit = ref({} as PaginatedProposalDeposit)
|
||||
store.fetchProposalDeposits(props.proposal_id).then(x => deposit.value = x)
|
||||
const deposit = ref({} as PaginatedProposalDeposit);
|
||||
store.fetchProposalDeposits(props.proposal_id).then((x) => (deposit.value = x));
|
||||
|
||||
const votes = ref({} as GovVote[])
|
||||
const votePage = ref({} as Pagination)
|
||||
const loading = ref(false)
|
||||
const votes = ref({} as GovVote[]);
|
||||
const votePage = ref({} as Pagination);
|
||||
const loading = ref(false);
|
||||
|
||||
store.fetchProposalVotes(props.proposal_id).then(x => {
|
||||
votes.value = x.votes
|
||||
votePage.value = x.pagination
|
||||
})
|
||||
store.fetchProposalVotes(props.proposal_id).then((x) => {
|
||||
votes.value = x.votes;
|
||||
votePage.value = x.pagination;
|
||||
});
|
||||
|
||||
function loadMore() {
|
||||
if(votePage.value.next_key) {
|
||||
loading.value = true
|
||||
store.fetchProposalVotes(props.proposal_id, votePage.value.next_key).then(x => {
|
||||
votes.value = votes.value.concat(x.votes)
|
||||
votePage.value = x.pagination
|
||||
loading.value = false
|
||||
})
|
||||
}
|
||||
if (votePage.value.next_key) {
|
||||
loading.value = true;
|
||||
store
|
||||
.fetchProposalVotes(props.proposal_id, votePage.value.next_key)
|
||||
.then((x) => {
|
||||
votes.value = votes.value.concat(x.votes);
|
||||
votePage.value = x.pagination;
|
||||
loading.value = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function shortTime(v: string) {
|
||||
if(v) {
|
||||
return format.toDay(v, "from")
|
||||
}
|
||||
return ""
|
||||
if (v) {
|
||||
return format.toDay(v, 'from');
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
const votingCountdown = computed((): number => {
|
||||
const now = new Date();
|
||||
const end = new Date(proposal.value.voting_end_time)
|
||||
return end.getTime() - now.getTime()
|
||||
})
|
||||
const now = new Date();
|
||||
const end = new Date(proposal.value.voting_end_time);
|
||||
return end.getTime() - now.getTime();
|
||||
});
|
||||
|
||||
const upgradeCountdown = computed((): number => {
|
||||
const height = Number(proposal.value.content?.plan?.height || 0)
|
||||
if(height > 0) {
|
||||
const base = useBaseStore()
|
||||
const current = Number(base.latest?.block?.header?.height || 0)
|
||||
return (height - current) * 6 * 1000
|
||||
}
|
||||
const now = new Date();
|
||||
const end = new Date(proposal.value.content?.plan?.time || "")
|
||||
return end.getTime() - now.getTime()
|
||||
})
|
||||
const height = Number(proposal.value.content?.plan?.height || 0);
|
||||
if (height > 0) {
|
||||
const base = useBaseStore();
|
||||
const current = Number(base.latest?.block?.header?.height || 0);
|
||||
return (height - current) * 6 * 1000;
|
||||
}
|
||||
const now = new Date();
|
||||
const end = new Date(proposal.value.content?.plan?.time || '');
|
||||
return end.getTime() - now.getTime();
|
||||
});
|
||||
|
||||
const total = computed(()=> {
|
||||
const tally = proposal.value.final_tally_result
|
||||
let sum = 0
|
||||
if(tally) {
|
||||
sum += Number(tally.abstain || 0)
|
||||
sum += Number(tally.yes || 0)
|
||||
sum += Number(tally.no || 0)
|
||||
sum += Number(tally.no_with_veto || 0)
|
||||
|
||||
}
|
||||
return sum
|
||||
})
|
||||
const total = computed(() => {
|
||||
const tally = proposal.value.final_tally_result;
|
||||
let sum = 0;
|
||||
if (tally) {
|
||||
sum += Number(tally.abstain || 0);
|
||||
sum += Number(tally.yes || 0);
|
||||
sum += Number(tally.no || 0);
|
||||
sum += Number(tally.no_with_veto || 0);
|
||||
}
|
||||
return sum;
|
||||
});
|
||||
|
||||
const turnout = computed(() => {
|
||||
if (total.value > 0) {
|
||||
const bonded = useStakingStore().pool?.bonded_tokens || "1"
|
||||
return format.percent(total.value / Number(bonded))
|
||||
}
|
||||
return 0
|
||||
})
|
||||
if (total.value > 0) {
|
||||
const bonded = useStakingStore().pool?.bonded_tokens || '1';
|
||||
return format.percent(total.value / Number(bonded));
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
|
||||
const yes = computed(()=> {
|
||||
if(total.value > 0) {
|
||||
const yes = proposal.value?.final_tally_result?.yes || 0
|
||||
return format.percent(Number(yes) / total.value )
|
||||
}
|
||||
return 0
|
||||
})
|
||||
const yes = computed(() => {
|
||||
if (total.value > 0) {
|
||||
const yes = proposal.value?.final_tally_result?.yes || 0;
|
||||
return format.percent(Number(yes) / total.value);
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
|
||||
const no = computed(()=> {
|
||||
if(total.value > 0) {
|
||||
const value = proposal.value?.final_tally_result?.no || 0
|
||||
return format.percent(Number(value) / total.value)
|
||||
}
|
||||
return 0
|
||||
})
|
||||
const no = computed(() => {
|
||||
if (total.value > 0) {
|
||||
const value = proposal.value?.final_tally_result?.no || 0;
|
||||
return format.percent(Number(value) / total.value);
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
|
||||
const veto = computed(()=> {
|
||||
if(total.value > 0) {
|
||||
const value = proposal.value?.final_tally_result?.no_with_veto || 0
|
||||
return format.percent(Number(value) / total.value)
|
||||
}
|
||||
return 0
|
||||
})
|
||||
const veto = computed(() => {
|
||||
if (total.value > 0) {
|
||||
const value = proposal.value?.final_tally_result?.no_with_veto || 0;
|
||||
return format.percent(Number(value) / total.value);
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
|
||||
const abstain = computed(()=> {
|
||||
if(total.value > 0) {
|
||||
const value = proposal.value?.final_tally_result?.abstain || 0
|
||||
return format.percent(Number(value) / total.value)
|
||||
}
|
||||
return 0
|
||||
})
|
||||
const processList = computed(()=>{
|
||||
return [
|
||||
{name: 'Turnout', value : turnout.value, class: 'bg-info' },
|
||||
{name: 'Yes', value : yes.value, class: 'bg-success' },
|
||||
{name: 'No', value : no.value, class: 'bg-error' },
|
||||
{name: 'No With Veto', value : veto.value, class: 'bg-primary' },
|
||||
{name: 'Abstain', value : abstain.value, class: 'bg-warning' }
|
||||
]
|
||||
})
|
||||
const abstain = computed(() => {
|
||||
if (total.value > 0) {
|
||||
const value = proposal.value?.final_tally_result?.abstain || 0;
|
||||
return format.percent(Number(value) / total.value);
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
const processList = computed(() => {
|
||||
return [
|
||||
{ name: 'Turnout', value: turnout.value, class: 'bg-info' },
|
||||
{ name: 'Yes', value: yes.value, class: 'bg-success' },
|
||||
{ name: 'No', value: no.value, class: 'bg-error' },
|
||||
{ name: 'No With Veto', value: veto.value, class: 'bg-primary' },
|
||||
{ name: 'Abstain', value: abstain.value, class: 'bg-warning' },
|
||||
];
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<div>
|
||||
<div class="bg-base-100 px-4 pt-3 pb-4 rounded mb-4 shadow">
|
||||
<h2 class="card-title flex flex-col md:justify-between md:flex-row">
|
||||
<p class="truncate w-full">{{ proposal_id }}. {{ proposal.content?.title }} </p>
|
||||
<div
|
||||
class="badge badge-ghost"
|
||||
:class="
|
||||
color === 'success'
|
||||
? 'text-yes'
|
||||
: color === 'error'
|
||||
? 'text-no'
|
||||
: 'text-info'
|
||||
"
|
||||
>{{ status }}</div>
|
||||
</h2>
|
||||
<div class="">
|
||||
<ObjectElement :value="proposal.content"/>
|
||||
<h2 class="card-title flex flex-col md:justify-between md:flex-row">
|
||||
<p class="truncate w-full">
|
||||
{{ proposal_id }}. {{ proposal.content?.title }}
|
||||
</p>
|
||||
<div
|
||||
class="badge badge-ghost"
|
||||
:class="
|
||||
color === 'success'
|
||||
? 'text-yes'
|
||||
: color === 'error'
|
||||
? 'text-no'
|
||||
: 'text-info'
|
||||
"
|
||||
>
|
||||
{{ status }}
|
||||
</div>
|
||||
</h2>
|
||||
<div class="">
|
||||
<ObjectElement :value="proposal.content" />
|
||||
</div>
|
||||
</div>
|
||||
<!-- grid lg:grid-cols-3 auto-rows-max-->
|
||||
<!-- flex-col lg:flex-row flex -->
|
||||
<div class="gap-4 mb-4 grid lg:grid-cols-3 auto-rows-max ">
|
||||
<!-- flex-1 -->
|
||||
<div class="bg-base-100 px-4 pt-3 pb-4 rounded shadow ">
|
||||
<h2 class="card-title">Tally</h2>
|
||||
<div v-for="(item,index) of processList" :key="index">
|
||||
<label class="block">{{item.name }}</label>
|
||||
<div class="h-6 w-full relative">
|
||||
<div class="absolute inset-x-0 inset-y-0 w-full opacity-10 rounded-sm" :class="`${item.class}`"></div>
|
||||
<div class="absolute inset-x-0 inset-y-0 rounded-sm" :class="`${item.class}`" :style="`width: ${item.value}`"></div>
|
||||
<p class="absolute inset-x-0 inset-y-0 text-center text-sm text-[#666] dark:text-[#eee] flex items-center justify-center">{{ item.value }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label for="vote" class="btn btn-primary float-right btn-sm mx-1" @click="dialog.open('vote', {proposal_id})">Vote</label>
|
||||
<label for="deposit" class="btn btn-primary float-right btn-sm mx-1" @click="dialog.open('deposit', {proposal_id})">Deposit</label>
|
||||
</div>
|
||||
<div class="gap-4 mb-4 grid lg:grid-cols-3 auto-rows-max">
|
||||
<!-- flex-1 -->
|
||||
<div class="bg-base-100 px-4 pt-3 pb-4 rounded shadow">
|
||||
<h2 class="card-title mb-1">Tally</h2>
|
||||
<div class="mb-1" v-for="(item, index) of processList" :key="index">
|
||||
<label class="block text-sm mb-1">{{ item.name }}</label>
|
||||
<div class="h-5 w-full relative">
|
||||
<div
|
||||
class="absolute inset-x-0 inset-y-0 w-full opacity-10 rounded-sm"
|
||||
:class="`${item.class}`"
|
||||
></div>
|
||||
<div
|
||||
class="absolute inset-x-0 inset-y-0 rounded-sm"
|
||||
:class="`${item.class}`"
|
||||
:style="`width: ${item.value}`"
|
||||
></div>
|
||||
<p
|
||||
class="absolute inset-x-0 inset-y-0 text-center text-sm text-[#666] dark:text-[#eee] flex items-center justify-center"
|
||||
>
|
||||
{{ item.value }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- lg:col-span-2 -->
|
||||
<!-- lg:flex-[2_2_0%] -->
|
||||
<div class="h-max bg-base-100 px-4 pt-3 pb-4 rounded shadow lg:col-span-2">
|
||||
<h2 class="card-title">Timeline</h2>
|
||||
<VTimeline
|
||||
class="mt-2"
|
||||
side="end"
|
||||
align="start"
|
||||
line-inset="8"
|
||||
truncate-line="both"
|
||||
density="compact"
|
||||
>
|
||||
<VTimelineItem
|
||||
dot-color="error"
|
||||
size="x-small"
|
||||
>
|
||||
<!-- 👉 Header -->
|
||||
<div class="d-flex justify-space-between flex-wrap mb-3">
|
||||
<h6 class="text-base font-weight-medium me-3">
|
||||
Submited at: {{ format.toDay(proposal.submit_time) }}
|
||||
</h6>
|
||||
<small class="text-xs text-disabled my-1">{{ shortTime(proposal.submit_time) }}</small>
|
||||
</div>
|
||||
</VTimelineItem>
|
||||
|
||||
<VTimelineItem
|
||||
size="x-small"
|
||||
dot-color="primary"
|
||||
>
|
||||
<!-- 👉 Header -->
|
||||
<div class="d-flex justify-space-between flex-wrap mb-3">
|
||||
<h6 class="text-base font-weight-medium me-3">
|
||||
Deposited at: {{ format.toDay(proposal.status==="PROPOSAL_STATUS_DEPOSIT_PERIOD"?proposal.deposit_end_time: proposal.voting_start_time) }}
|
||||
</h6>
|
||||
<small class="text-xs text-disabled text-no-wrap my-1">{{ shortTime(proposal.status==="PROPOSAL_STATUS_DEPOSIT_PERIOD"?proposal.deposit_end_time: proposal.voting_start_time) }}</small>
|
||||
</div>
|
||||
|
||||
<p class="mb-0">
|
||||
<div v-for="x of deposit.deposits">
|
||||
{{ x.depositor }} {{ format.formatTokens(x.amount) }}
|
||||
</div>
|
||||
</p>
|
||||
|
||||
|
||||
</VTimelineItem>
|
||||
|
||||
<VTimelineItem
|
||||
size="x-small"
|
||||
dot-color="success"
|
||||
>
|
||||
<!-- 👉 Header -->
|
||||
<div class="d-flex justify-space-between flex-wrap mb-3">
|
||||
<h6 class="text-base font-weight-medium me-3">
|
||||
Voting start from {{ format.toDay(proposal.voting_start_time) }}
|
||||
</h6>
|
||||
<small class="text-xs text-disabled text-no-wrap my-1">{{ shortTime(proposal.voting_start_time) }}</small>
|
||||
</div>
|
||||
|
||||
<!-- 👉 Content -->
|
||||
<p class="mb-0">
|
||||
<Countdown :time="votingCountdown"/>
|
||||
</p>
|
||||
</VTimelineItem>
|
||||
|
||||
<VTimelineItem
|
||||
size="x-small"
|
||||
dot-color="success"
|
||||
>
|
||||
<!-- 👉 Header -->
|
||||
<div class="d-flex justify-space-between flex-wrap mb-3">
|
||||
<h6 class="text-base font-weight-medium me-3">
|
||||
Voting end {{ format.toDay(proposal.voting_end_time) }}
|
||||
</h6>
|
||||
<small class="text-xs text-disabled text-no-wrap my-1">{{ shortTime(proposal.voting_end_time) }}</small>
|
||||
</div>
|
||||
|
||||
<!-- 👉 Content -->
|
||||
<p class="mb-0">
|
||||
Current Status: {{ proposal.status }}
|
||||
</p>
|
||||
</VTimelineItem>
|
||||
<VTimelineItem
|
||||
v-if="proposal.content && proposal.content['@type'].endsWith('SoftwareUpgradeProposal')"
|
||||
size="x-small"
|
||||
dot-color="success"
|
||||
>
|
||||
<!-- 👉 Header -->
|
||||
<div class="d-flex justify-space-between flex-wrap mb-3">
|
||||
<h6 class="text-base font-weight-medium me-3">
|
||||
Upgrade Plan:
|
||||
<span v-if="Number(proposal.content?.plan?.height||'0') > 0"> (EST)</span>
|
||||
<span v-else>{{ format.toDay(proposal.content?.plan?.time) }}</span>
|
||||
</h6>
|
||||
<small class="text-xs text-disabled text-no-wrap my-1">{{ shortTime(proposal.voting_end_time) }}</small>
|
||||
</div>
|
||||
|
||||
<!-- 👉 Content -->
|
||||
<p class="mb-0">
|
||||
<Countdown :time="upgradeCountdown"/>
|
||||
</p>
|
||||
</VTimelineItem>
|
||||
</VTimeline>
|
||||
<div class="mt-6 grid grid-cols-2">
|
||||
<label
|
||||
for="vote"
|
||||
class="btn btn-primary float-right btn-sm mx-1"
|
||||
@click="dialog.open('vote', { proposal_id })"
|
||||
>Vote</label
|
||||
>
|
||||
<label
|
||||
for="deposit"
|
||||
class="btn btn-primary float-right btn-sm mx-1"
|
||||
@click="dialog.open('deposit', { proposal_id })"
|
||||
>Deposit</label
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="bg-base-100 px-4 pt-3 pb-5 rounded shadow lg:col-span-2"
|
||||
>
|
||||
<h2 class="card-title">Timeline</h2>
|
||||
|
||||
<div class="px-1">
|
||||
<div class="flex items-center mb-4 mt-2">
|
||||
<div class="w-2 h-2 rounded-full bg-error mr-3"></div>
|
||||
<div class="text-base flex-1 text-main">
|
||||
Submited at: {{ format.toDay(proposal.submit_time) }}
|
||||
</div>
|
||||
<div class="text-sm">{{ shortTime(proposal.submit_time) }}</div>
|
||||
</div>
|
||||
<div class="flex items-center mb-4">
|
||||
<div class="w-2 h-2 rounded-full bg-primary mr-3"></div>
|
||||
<div class="text-base flex-1 text-main">
|
||||
Deposited at:
|
||||
{{
|
||||
format.toDay(
|
||||
proposal.status === 'PROPOSAL_STATUS_DEPOSIT_PERIOD'
|
||||
? proposal.deposit_end_time
|
||||
: proposal.voting_start_time
|
||||
)
|
||||
}}
|
||||
</div>
|
||||
<div class="text-sm">
|
||||
{{
|
||||
shortTime(
|
||||
proposal.status === 'PROPOSAL_STATUS_DEPOSIT_PERIOD'
|
||||
? proposal.deposit_end_time
|
||||
: proposal.voting_start_time
|
||||
)
|
||||
}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-4">
|
||||
<div class="flex items-center">
|
||||
<div class="w-2 h-2 rounded-full bg-yes mr-3"></div>
|
||||
<div class="text-base flex-1 text-main">
|
||||
Voting start from {{ format.toDay(proposal.voting_start_time) }}
|
||||
</div>
|
||||
<div class="text-sm">
|
||||
{{ shortTime(proposal.voting_start_time) }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="pl-5 text-sm mt-2">
|
||||
<Countdown :time="votingCountdown" />
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="flex items-center mb-1">
|
||||
<div class="w-2 h-2 rounded-full bg-success mr-3"></div>
|
||||
<div class="text-base flex-1 text-main">
|
||||
Voting end {{ format.toDay(proposal.voting_end_time) }}
|
||||
</div>
|
||||
<div class="text-sm">
|
||||
{{ shortTime(proposal.voting_end_time) }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="pl-5 text-sm">
|
||||
Current Status: {{ proposal.status }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="mt-4"
|
||||
v-if="
|
||||
proposal?.content?.['@type']?.endsWith('SoftwareUpgradeProposal')
|
||||
"
|
||||
>
|
||||
<div class="flex items-center">
|
||||
<div class="w-2 h-2 rounded-full bg-warning mr-3"></div>
|
||||
<div class="text-base flex-1 text-main">
|
||||
Upgrade Plan:
|
||||
<span v-if="Number(proposal.content?.plan?.height || '0') > 0">
|
||||
(EST)</span
|
||||
>
|
||||
<span v-else>{{
|
||||
format.toDay(proposal.content?.plan?.time)
|
||||
}}</span>
|
||||
</div>
|
||||
<div class="text-sm">
|
||||
{{ shortTime(proposal.voting_end_time) }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="pl-5 text-sm mt-2">
|
||||
<Countdown :time="upgradeCountdown" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="bg-base-100 px-4 pt-3 pb-4 rounded mb-4 shadow">
|
||||
<h2 class="card-title">Votes</h2>
|
||||
<div class="overflow-x-auto">
|
||||
<table class="table w-full">
|
||||
<tbody>
|
||||
<tr v-for="(item,index) of votes" :key="index">
|
||||
<td>{{ item.voter }}</td>
|
||||
<td>{{ item.option }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h2 class="card-title">Votes</h2>
|
||||
<div class="overflow-x-auto">
|
||||
<table class="table w-full table-zebra">
|
||||
<tbody>
|
||||
<tr v-for="(item, index) of votes" :key="index">
|
||||
<td class="py-2 text-sm">{{ item.voter }}</td>
|
||||
<td
|
||||
class="py-2 text-sm"
|
||||
:class="{
|
||||
'text-yes': item.option === 'VOTE_OPTION_YES',
|
||||
'text-gray-400': item.option === 'VOTE_OPTION_ABSTAIN',
|
||||
}"
|
||||
>
|
||||
{{ item.option }}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<button
|
||||
v-if="votePage.next_key"
|
||||
@click="loadMore()"
|
||||
:disabled="loading"
|
||||
class="btn btn-outline btn-primary w-full"
|
||||
style="border: 1px solid hsl(var(--p));"
|
||||
>Load more</button>
|
||||
</div>
|
||||
<button
|
||||
@click="loadMore()"
|
||||
v-if="votePage.next_key"
|
||||
:disabled="loading"
|
||||
class="btn btn-outline btn-primary w-full mt-4"
|
||||
>
|
||||
Load more
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -7,7 +7,7 @@ const store = useGovStore();
|
||||
|
||||
onMounted(() => {
|
||||
store.fetchProposals('2').then((x) => {
|
||||
if (x.proposals.length === 0) {
|
||||
if (x?.proposals?.length === 0) {
|
||||
tab.value = '3';
|
||||
store.fetchProposals('3');
|
||||
}
|
||||
|
@ -106,7 +106,7 @@ function color(v: string) {
|
||||
<table class="table w-full mt-4">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="position: relative">Channel Id</th>
|
||||
<th style="position: relative; z-index: 2;">Channel Id</th>
|
||||
<th>Port Id</th>
|
||||
<th>Counterparty</th>
|
||||
<th>Hops</th>
|
||||
|
@ -28,7 +28,7 @@ function color(v: string) {
|
||||
<table class="table w-full">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="position: relative">Connection Id</th>
|
||||
<th style="position: relative; z-index: 2;">Connection Id</th>
|
||||
<th>Connection</th>
|
||||
<th>Delay Period</th>
|
||||
<th>State</th>
|
||||
|
@ -146,14 +146,14 @@ export const useIndexModule = defineStore('module-index', {
|
||||
title: 'Height',
|
||||
color: 'primary',
|
||||
icon: 'mdi-pound',
|
||||
stats: String(base.latest.block?.header?.height || 0),
|
||||
stats: String(base?.latest?.block?.header?.height || 0),
|
||||
change: 0,
|
||||
},
|
||||
{
|
||||
title: 'Validators',
|
||||
color: 'error',
|
||||
icon: 'mdi-human-queue',
|
||||
stats: String(base.latest.block?.last_commit?.signatures.length || 0),
|
||||
stats: String(base?.latest?.block?.last_commit?.signatures.length || 0),
|
||||
change: 0,
|
||||
},
|
||||
{
|
||||
@ -202,9 +202,9 @@ export const useIndexModule = defineStore('module-index', {
|
||||
useDistributionStore()
|
||||
.fetchCommunityPool()
|
||||
.then((x) => {
|
||||
this.communityPool = x.pool
|
||||
.filter((t) => t.denom.length < 10)
|
||||
.map((t) => ({
|
||||
this.communityPool = x?.pool
|
||||
?.filter((t) => t.denom.length < 10)
|
||||
?.map((t) => ({
|
||||
amount: String(parseInt(t.amount)),
|
||||
denom: t.denom,
|
||||
}));
|
||||
|
@ -136,7 +136,7 @@ onMounted(() => {
|
||||
<template>
|
||||
<div>
|
||||
<div class="bg-base-100 px-4 pt-3 pb-4 rounded shadow border-indigo-500">
|
||||
<div class="flex flex-col lg:flex-row">
|
||||
<div class="flex flex-col lg:flex-row pt-2 pb-1">
|
||||
<div class="flex-1">
|
||||
<div class="flex">
|
||||
<div class="avatar mr-4 relative w-24 rounded-lg overflow-hidden">
|
||||
@ -158,7 +158,7 @@ onMounted(() => {
|
||||
</div>
|
||||
<div class="mx-2">
|
||||
<h4>{{ v.description?.moniker }}</h4>
|
||||
<div class="text-sm mb-2">
|
||||
<div class="text-sm mb-4">
|
||||
{{ v.description?.identity || '-' }}
|
||||
</div>
|
||||
<label
|
||||
@ -174,41 +174,46 @@ onMounted(() => {
|
||||
</div>
|
||||
</div>
|
||||
<div class="m-4 text-sm">
|
||||
<p class="text-md">About Us</p>
|
||||
<VList class="card-list">
|
||||
<VListItem prepend-icon="mdi-web">
|
||||
<span>Website: </span
|
||||
><span> {{ v.description?.website || '-' }}</span>
|
||||
</VListItem>
|
||||
<VListItem prepend-icon="mdi-email-outline">
|
||||
<span>Contact: </span
|
||||
><span> {{ v.description?.security_contact }}</span>
|
||||
</VListItem>
|
||||
</VList>
|
||||
<p class="text-md mt-3">Validator Status</p>
|
||||
<VList class="card-list">
|
||||
<VListItem prepend-icon="mdi-shield-account-outline">
|
||||
<p class="text-sm mb-3">About Us</p>
|
||||
<div class="card-list">
|
||||
<div class="flex items-center mb-2">
|
||||
<Icon icon="mdi-web" class="text-xl mr-1" />
|
||||
<span>Website: </span>
|
||||
<span> {{ v.description?.website || '-' }}</span>
|
||||
</div>
|
||||
<div class="flex items-center">
|
||||
<Icon icon="mdi-email-outline" class="text-xl mr-1" />
|
||||
<span>Contact: </span>
|
||||
<span> {{ v.description?.security_contact }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-sm mt-4 mb-3">Validator Status</p>
|
||||
<div class="card-list">
|
||||
<div class="flex items-center mb-2">
|
||||
<Icon icon="mdi-shield-account-outline" class="text-xl mr-1" />
|
||||
<span>Status: </span
|
||||
><span>
|
||||
{{ String(v.status).replace('BOND_STATUS_', '') }}
|
||||
</span>
|
||||
</VListItem>
|
||||
<VListItem prepend-icon="mdi-shield-alert-outline">
|
||||
<span>Jailed: </span><span> {{ v.jailed || '-' }} </span>
|
||||
</VListItem>
|
||||
</VList>
|
||||
</div>
|
||||
<div class="flex items-center">
|
||||
<Icon icon="mdi-shield-alert-outline" class="text-xl mr-1" />
|
||||
<span>Jailed: </span>
|
||||
<span> {{ v.jailed || '-' }} </span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<div class="d-flex flex-column py-3 justify-space-between">
|
||||
<div class="d-flex">
|
||||
<VAvatar
|
||||
color="secondary"
|
||||
rounded
|
||||
variant="outlined"
|
||||
icon="mdi-coin"
|
||||
></VAvatar>
|
||||
<div class="ml-3 d-flex flex-column justify-center">
|
||||
<div class="flex flex-col justify-between">
|
||||
<div class="flex mb-2">
|
||||
<div
|
||||
class="flex items-center justify-center rounded w-10 h-10"
|
||||
style="border: 1px solid #666"
|
||||
>
|
||||
<Icon icon="mdi-coin" class="text-3xl" />
|
||||
</div>
|
||||
<div class="ml-3 flex flex-col justify-center">
|
||||
<h4>
|
||||
{{
|
||||
format.formatToken2({
|
||||
@ -220,14 +225,14 @@ onMounted(() => {
|
||||
<span class="text-sm">Total Bonded Tokens</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex">
|
||||
<VAvatar
|
||||
color="secondary"
|
||||
rounded
|
||||
variant="outlined"
|
||||
icon="mdi-percent"
|
||||
></VAvatar>
|
||||
<div class="ml-3 d-flex flex-column justify-center">
|
||||
<div class="flex mb-2">
|
||||
<div
|
||||
class="flex items-center justify-center rounded w-10 h-10"
|
||||
style="border: 1px solid #666"
|
||||
>
|
||||
<Icon icon="mdi-percent" class="text-3xl" />
|
||||
</div>
|
||||
<div class="ml-3 flex flex-col justify-center">
|
||||
<h4>
|
||||
{{ format.formatToken(selfBonded.balance) }} ({{ selfRate }})
|
||||
</h4>
|
||||
@ -235,13 +240,14 @@ onMounted(() => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="d-flex">
|
||||
<VAvatar
|
||||
color="secondary"
|
||||
rounded
|
||||
variant="outlined"
|
||||
icon="mdi-account-tie"
|
||||
></VAvatar>
|
||||
<div class="flex mb-2">
|
||||
<div
|
||||
class="flex items-center justify-center rounded w-10 h-10"
|
||||
style="border: 1px solid #666"
|
||||
>
|
||||
<Icon icon="mdi-account-tie" class="text-3xl" />
|
||||
</div>
|
||||
|
||||
<div class="ml-3 d-flex flex-column justify-center">
|
||||
<h4>
|
||||
{{ v.min_self_delegation }} {{ staking.params.bond_denom }}
|
||||
@ -249,40 +255,40 @@ onMounted(() => {
|
||||
<span class="text-sm">Min Self Delegation:</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex">
|
||||
<VAvatar
|
||||
color="secondary"
|
||||
rounded
|
||||
variant="outlined"
|
||||
icon="mdi-finance"
|
||||
></VAvatar>
|
||||
<div class="ml-3 d-flex flex-column justify-center">
|
||||
<div class="flex mb-2">
|
||||
<div
|
||||
class="flex items-center justify-center rounded w-10 h-10"
|
||||
style="border: 1px solid #666"
|
||||
>
|
||||
<Icon icon="mdi-finance" class="text-3xl" />
|
||||
</div>
|
||||
<div class="ml-3 flex flex-col justify-center">
|
||||
<h4>{{ apr }}</h4>
|
||||
<span class="text-sm">Annual Profit</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="d-flex">
|
||||
<VAvatar
|
||||
color="secondary"
|
||||
rounded
|
||||
variant="outlined"
|
||||
icon="mdi-stairs-up"
|
||||
></VAvatar>
|
||||
<div class="ml-3 d-flex flex-column justify-center">
|
||||
<div class="flex mb-2">
|
||||
<div
|
||||
class="flex items-center justify-center rounded w-10 h-10"
|
||||
style="border: 1px solid #666"
|
||||
>
|
||||
<Icon icon="mdi-stairs-up" class="text-3xl" />
|
||||
</div>
|
||||
<div class="ml-3 flex flex-col justify-center">
|
||||
<h4>{{ v.unbonding_height }}</h4>
|
||||
<span class="text-sm">Unbonding Height</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="d-flex">
|
||||
<VAvatar
|
||||
color="secondary"
|
||||
rounded
|
||||
variant="outlined"
|
||||
icon="mdi-clock"
|
||||
></VAvatar>
|
||||
<div class="ml-3 d-flex flex-column justify-center">
|
||||
<div class="flex mb-2">
|
||||
<div
|
||||
class="flex items-center justify-center rounded w-10 h-10"
|
||||
style="border: 1px solid #666"
|
||||
>
|
||||
<Icon icon="mdi-clock" class="text-3xl" />
|
||||
</div>
|
||||
<div class="ml-3 flex flex-col justify-center">
|
||||
<h4>{{ format.toDay(v.unbonding_time, 'from') }}</h4>
|
||||
<span class="text-sm">Unbonding Time</span>
|
||||
</div>
|
||||
@ -290,8 +296,7 @@ onMounted(() => {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="divider"></div>
|
||||
<div class="text-sm px-4">{{ v.description?.details }}</div>
|
||||
<div class="text-sm px-4 pt-3 border-t">{{ v.description?.details }}</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-3 grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||
|
@ -49,7 +49,7 @@ const messages = computed(() => {
|
||||
<tr>
|
||||
<td>Status</td>
|
||||
<td>
|
||||
<VChip color="primary">oioio</VChip>
|
||||
<div class="badge badge-primary badge-sm">oioio</div>
|
||||
<div
|
||||
class="text-xs truncate relative py-2 px-4 rounded-full w-fit mr-2"
|
||||
:class="`text-${
|
||||
|
@ -106,12 +106,15 @@ watchEffect(() => {
|
||||
class="input input-sm w-full flex-1"
|
||||
/>
|
||||
<button class="btn btn-primary btn-sm">
|
||||
<Icon icon="mdi-star" class="mr-2 text-lg" /> <span class="">Favorite</span>
|
||||
<Icon icon="mdi-star" class="mr-2 text-lg" />
|
||||
<span class="">Favorite</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-2 md:grid-cols-3 xl:grid-cols-4 gap-4 mt-4">
|
||||
<div v-for="(v, i) in validators">
|
||||
<div
|
||||
class="grid grid-cols-2 md:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-6 gap-x-4 mt-4"
|
||||
>
|
||||
<div v-for="(v, i) in validators" :key="i">
|
||||
<div class="flex items-center justify-between">
|
||||
<VCheckbox
|
||||
v-model="selected"
|
||||
@ -119,7 +122,7 @@ watchEffect(() => {
|
||||
:value="v.operator_address"
|
||||
>
|
||||
<template v-slot:label>
|
||||
<span class="text-truncate"
|
||||
<span class="text-truncate text-sm"
|
||||
>{{ i + 1 }}. {{ v.description.moniker }}</span
|
||||
>
|
||||
</template>
|
||||
|
@ -1,52 +1,27 @@
|
||||
<script setup lang="ts">
|
||||
import misc404 from '@images/pages/404.png';
|
||||
|
||||
import miscObj from '@images/pages/misc-404-object.png';
|
||||
import miscMaskDark from '@images/pages/misc-mask-dark.png';
|
||||
import miscMaskLight from '@images/pages/misc-mask-light.png';
|
||||
|
||||
import { useGenerateImageVariant } from '@/plugins/vuetify/@core/composable/useGenerateImageVariant';
|
||||
|
||||
const miscThemeMask = useGenerateImageVariant(miscMaskLight, miscMaskDark);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="misc-wrapper">
|
||||
<ErrorHeader
|
||||
error-code="404"
|
||||
error-title="Page Not Found ⚠️"
|
||||
error-description="We couldn't find the page you are looking for."
|
||||
/>
|
||||
<div class="pt-10">
|
||||
<div class="text-center">
|
||||
<div class="text-8xl font-semibold text-main">404</div>
|
||||
<div class="text-xl font-bold my-2">Page Not Found</div>
|
||||
<div class="text-base">
|
||||
We couldn't find the page you are looking for.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 👉 Image -->
|
||||
<div class="misc-avatar w-100 text-center">
|
||||
<VImg
|
||||
:src="misc404"
|
||||
alt="Coming Soon"
|
||||
:height="$vuetify.display.xs ? 400 : 500"
|
||||
class="my-sm-4"
|
||||
/>
|
||||
<VBtn to="/" class="mt-10"> Back to Home </VBtn>
|
||||
<VImg
|
||||
:src="miscThemeMask"
|
||||
class="d-none d-md-block footer-coming-soon"
|
||||
cover
|
||||
/>
|
||||
|
||||
<VImg
|
||||
:src="miscObj"
|
||||
class="d-none d-md-block footer-coming-soon-obj"
|
||||
:max-width="174"
|
||||
height="158"
|
||||
/>
|
||||
<RouterLink to="/" class="btn no-underline btn-primary mt-4">
|
||||
Back to Home
|
||||
</RouterLink>
|
||||
<img :src="misc404" alt="Coming Soon" class="mx-auto h-[400px] mt-10" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
@use '@core/scss/template/pages/misc.scss';
|
||||
</style>
|
||||
|
||||
<route lang="yaml">
|
||||
meta:
|
||||
layout: blank
|
||||
|
@ -1,17 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<VCard title="Create Awesome 🙌">
|
||||
<VCardText>This is your second page.</VCardText>
|
||||
<VCardText>
|
||||
Chocolate sesame snaps pie carrot cake pastry pie lollipop muffin.
|
||||
Carrot cake dragée chupa chups jujubes. Macaroon liquorice cookie wafer
|
||||
tart marzipan bonbon. Gingerbread jelly-o dragée chocolate.
|
||||
</VCardText>
|
||||
</VCard>
|
||||
</div>
|
||||
</template>
|
||||
<route lang="yaml">
|
||||
meta:
|
||||
layout: blank
|
||||
bgColor: yellow
|
||||
</route>
|
@ -33,11 +33,11 @@ export const useBaseStore = defineStore('baseStore', {
|
||||
return useBlockchain();
|
||||
},
|
||||
txsInRecents() {
|
||||
const txs = [] as { height: string, hash: string; tx: DecodedTxRaw }[];
|
||||
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)
|
||||
const raw = fromBase64(tx);
|
||||
try {
|
||||
txs.push({
|
||||
height: b.block.header.height,
|
||||
@ -45,7 +45,7 @@ export const useBaseStore = defineStore('baseStore', {
|
||||
tx: decodeTxRaw(raw),
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
})
|
||||
@ -61,18 +61,22 @@ export const useBaseStore = defineStore('baseStore', {
|
||||
this.recents = [];
|
||||
},
|
||||
async fetchLatest() {
|
||||
this.latest = await this.blockchain.rpc.getBaseBlockLatest();
|
||||
this.latest = await this.blockchain.rpc?.getBaseBlockLatest();
|
||||
if (
|
||||
!this.earlest ||
|
||||
this.earlest.block?.header?.chain_id !=
|
||||
this.latest.block?.header?.chain_id
|
||||
this.earlest?.block?.header?.chain_id !=
|
||||
this.latest?.block?.header?.chain_id
|
||||
) {
|
||||
//reset earlest and recents
|
||||
this.earlest = this.latest;
|
||||
this.recents = [];
|
||||
}
|
||||
//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.findIndex(
|
||||
(x) => x?.block_id?.hash === this.latest?.block_id?.hash
|
||||
) === -1
|
||||
) {
|
||||
if (this.recents.length >= 50) {
|
||||
this.recents.pop();
|
||||
}
|
||||
@ -87,7 +91,7 @@ export const useBaseStore = defineStore('baseStore', {
|
||||
async fetchLatestValidators(offset = 0) {
|
||||
return this.blockchain.rpc.getBaseValidatorsetLatest(offset);
|
||||
},
|
||||
async fetchBlock(height?: number|string) {
|
||||
async fetchBlock(height?: number | string) {
|
||||
return this.blockchain.rpc.getBaseBlockAt(String(height));
|
||||
},
|
||||
async fetchAbciInfo() {
|
||||
|
@ -12,7 +12,7 @@ export const useDistributionStore = defineStore('distributionStore', {
|
||||
},
|
||||
actions: {
|
||||
async fetchCommunityPool() {
|
||||
return this.blockchain.rpc.getDistributionCommunityPool();
|
||||
return this.blockchain.rpc?.getDistributionCommunityPool();
|
||||
},
|
||||
},
|
||||
});
|
||||
|
@ -54,8 +54,8 @@ export const useFormatter = defineStore('formatter', {
|
||||
return useBankStore();
|
||||
},
|
||||
dashboard() {
|
||||
return useDashboard()
|
||||
}
|
||||
return useDashboard();
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
async fetchDenomTrace(denom: string) {
|
||||
@ -69,9 +69,9 @@ export const useFormatter = defineStore('formatter', {
|
||||
return trace;
|
||||
},
|
||||
priceInfo(denom: string) {
|
||||
const id = this.dashboard.coingecko[denom]?.coinId
|
||||
const prices = this.dashboard.prices[id]
|
||||
return prices
|
||||
const id = this.dashboard.coingecko[denom]?.coinId;
|
||||
const prices = this.dashboard.prices[id];
|
||||
return prices;
|
||||
},
|
||||
priceColor(denom: string, currency = "usd") {
|
||||
const change = this.priceChanges(denom, currency)
|
||||
@ -86,11 +86,11 @@ export const useFormatter = defineStore('formatter', {
|
||||
},
|
||||
price(denom: string, currency = "usd") {
|
||||
const info = this.priceInfo(denom);
|
||||
return info? info[currency]||0 : 0
|
||||
return info ? info[currency] || 0 : 0;
|
||||
},
|
||||
priceChanges(denom: string, currency="usd"): number {
|
||||
priceChanges(denom: string, currency = 'usd'): number {
|
||||
const info = this.priceInfo(denom);
|
||||
return info? info[`${currency}_24h_change`]||0 : 0
|
||||
return info ? info[`${currency}_24h_change`] || 0 : 0;
|
||||
},
|
||||
showChanges(v: number) {
|
||||
return v!==0 ? numeral(v).format("+0,0.[00]"): ""
|
||||
@ -103,7 +103,8 @@ export const useFormatter = defineStore('formatter', {
|
||||
// find the symbol,
|
||||
const symbol = this.dashboard.coingecko[token.denom]?.symbol || ""
|
||||
// convert denomation to to symbol
|
||||
const exponent = this.dashboard.coingecko[symbol.toLowerCase()]?.exponent || 0
|
||||
const exponent =
|
||||
this.dashboard.coingecko[symbol.toLowerCase()]?.exponent || 0;
|
||||
// cacualte amount of symbol
|
||||
const amount = Number(token.amount) / (10 ** exponent)
|
||||
const value = amount * this.price(token.denom)
|
||||
@ -131,7 +132,7 @@ export const useFormatter = defineStore('formatter', {
|
||||
fmt = '0.0a',
|
||||
mode = 'local'
|
||||
): string {
|
||||
if (token && token.amount) {
|
||||
if (token && token.amount && token?.denom) {
|
||||
let amount = Number(token.amount);
|
||||
let denom = token.denom;
|
||||
|
||||
@ -241,11 +242,11 @@ export const useFormatter = defineStore('formatter', {
|
||||
}
|
||||
return dayjs(time).format('YYYY-MM-DD HH:mm:ss');
|
||||
},
|
||||
messages(msgs: { '@type'?: string, typeUrl?: string }[]) {
|
||||
messages(msgs: { '@type'?: string; typeUrl?: string }[]) {
|
||||
if (msgs) {
|
||||
const sum: Record<string, number> = msgs
|
||||
.map((msg) => {
|
||||
const msgType = msg['@type'] || msg.typeUrl || 'unknown'
|
||||
const msgType = msg['@type'] || msg.typeUrl || 'unknown';
|
||||
return msgType
|
||||
.substring(msgType.lastIndexOf('.') + 1)
|
||||
.replace('Msg', '');
|
||||
|
@ -31,10 +31,10 @@ export const useGovStore = defineStore('govStore', {
|
||||
if (!this.loading[status]) {
|
||||
this.loading[status] = LoadingStatus.Loading;
|
||||
const proposals = reactive(
|
||||
await this.blockchain.rpc.getGovProposals(status)
|
||||
await this.blockchain.rpc?.getGovProposals(status)
|
||||
);
|
||||
if (status === '2') {
|
||||
proposals.proposals.forEach(async (x1) => {
|
||||
proposals?.proposals?.forEach(async (x1) => {
|
||||
await this.fetchTally(x1.proposal_id).then((res) => {
|
||||
x1.final_tally_result = res?.tally;
|
||||
});
|
||||
|
@ -17,14 +17,16 @@ export const useMintStore = defineStore('mintStore', {
|
||||
this.fetchInflation();
|
||||
},
|
||||
async fetchInflation() {
|
||||
this.blockchain.rpc
|
||||
.getMintInflation()
|
||||
.then((x) => {
|
||||
this.inflation = x.inflation;
|
||||
})
|
||||
.catch(() => {
|
||||
try {
|
||||
const res = await this.blockchain?.rpc?.getMintInflation().catch(() => {
|
||||
this.inflation = '0';
|
||||
});
|
||||
if (res) {
|
||||
this.inflation = res.inflation;
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
@ -203,19 +203,19 @@ export const useParamStore = defineStore('paramstore', {
|
||||
console.log('handleAbciInfo', this.nodeVersion.items);
|
||||
},
|
||||
async getBaseTendermintBlockLatest() {
|
||||
return await this.blockchain.rpc.getBaseBlockLatest();
|
||||
return await this.blockchain.rpc?.getBaseBlockLatest();
|
||||
},
|
||||
async getMintParam() {
|
||||
return await this.blockchain.rpc.getMintParam();
|
||||
return await this.blockchain.rpc?.getMintParam();
|
||||
},
|
||||
async getStakingParams() {
|
||||
return await this.blockchain.rpc.getStakingParams();
|
||||
return await this.blockchain.rpc?.getStakingParams();
|
||||
},
|
||||
async getStakingPool() {
|
||||
return await this.blockchain.rpc.getStakingPool();
|
||||
return await this.blockchain.rpc?.getStakingPool();
|
||||
},
|
||||
async getBankTotal(denom: string) {
|
||||
return await this.blockchain.rpc.getBankSupplyByDenom(denom);
|
||||
return await this.blockchain.rpc?.getBankSupplyByDenom(denom);
|
||||
// if (compareVersions(this.config.sdk_version, '0.46.2') > 0) {
|
||||
// return this.get(`/cosmos/bank/v1beta1/supply/by_denom?denom=${denom}`).then(data => commonProcess(data).amount)
|
||||
// }
|
||||
@ -225,22 +225,22 @@ export const useParamStore = defineStore('paramstore', {
|
||||
// return this.get(`/cosmos/bank/v1beta1/supply/${denom}`).then(data => commonProcess(data).amount)
|
||||
},
|
||||
async getSlashingParams() {
|
||||
return await this.blockchain.rpc.getSlashingParams();
|
||||
return await this.blockchain.rpc?.getSlashingParams();
|
||||
},
|
||||
async getDistributionParams() {
|
||||
return await this.blockchain.rpc.getDistributionParams();
|
||||
return await this.blockchain.rpc?.getDistributionParams();
|
||||
},
|
||||
async getGovParamsVoting() {
|
||||
return await this.blockchain.rpc.getGovParamsVoting();
|
||||
return await this.blockchain.rpc?.getGovParamsVoting();
|
||||
},
|
||||
async getGovParamsDeposit() {
|
||||
return await this.blockchain.rpc.getGovParamsDeposit();
|
||||
return await this.blockchain.rpc?.getGovParamsDeposit();
|
||||
},
|
||||
async getGovParamsTally() {
|
||||
return await this.blockchain.rpc.getGovParamsTally();
|
||||
return await this.blockchain.rpc?.getGovParamsTally();
|
||||
},
|
||||
async fetchAbciInfo() {
|
||||
return this.blockchain.rpc.getBaseNodeInfo();
|
||||
return this.blockchain.rpc?.getBaseNodeInfo();
|
||||
},
|
||||
},
|
||||
});
|
||||
|
@ -47,14 +47,16 @@ export const useStakingStore = defineStore('stakingStore', {
|
||||
);
|
||||
},
|
||||
async fetchParams() {
|
||||
const response = await this.blockchain.rpc.getStakingParams();
|
||||
if (response.params) this.params = response.params;
|
||||
const response = await this.blockchain.rpc?.getStakingParams();
|
||||
if (response?.params) this.params = response.params;
|
||||
return this.params;
|
||||
},
|
||||
async fetchPool() {
|
||||
const response = await this.blockchain.rpc.getStakingPool();
|
||||
response.pool.bonded_tokens;
|
||||
this.pool = response.pool;
|
||||
const response = await this.blockchain.rpc?.getStakingPool();
|
||||
if (response) {
|
||||
response.pool.bonded_tokens;
|
||||
this.pool = response.pool;
|
||||
}
|
||||
},
|
||||
async fetchAcitveValdiators() {
|
||||
return this.fetchValidators('BOND_STATUS_BONDED');
|
||||
@ -69,13 +71,13 @@ export const useStakingStore = defineStore('stakingStore', {
|
||||
validatorAddr: string,
|
||||
delegatorAddr: string
|
||||
) {
|
||||
return await this.blockchain.rpc.getStakingValidatorsDelegationsDelegator(
|
||||
return await this.blockchain.rpc?.getStakingValidatorsDelegationsDelegator(
|
||||
validatorAddr,
|
||||
delegatorAddr
|
||||
);
|
||||
},
|
||||
async fetchValidators(status: string) {
|
||||
return this.blockchain.rpc.getStakingValidators(status).then((res) => {
|
||||
return this.blockchain.rpc?.getStakingValidators(status).then((res) => {
|
||||
const vals = res.validators.sort(
|
||||
(a, b) => Number(b.delegator_shares) - Number(a.delegator_shares)
|
||||
);
|
||||
|
@ -29,3 +29,8 @@
|
||||
:where(input[type='checkbox']:checked ~ .collapse-content) {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.table th:first-child {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
}
|
Loading…
Reference in New Issue
Block a user