forked from cerc-io/cosmos-explorer
Merge pull request #379 from alisaweb3/v3-single
UI refactor: Uptime, Staking,Dashboard,Validator Detail,Tx
This commit is contained in:
commit
e7a21a9db9
20
src/App.vue
20
src/App.vue
@ -23,15 +23,13 @@ onMounted(() => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<VLocaleProvider :rtl="isAppRtl">
|
||||
<!-- ℹ️ This is required to set the background color of active nav link based on currently active global theme's primary -->
|
||||
<VApp
|
||||
:style="`--v-global-theme-primary: ${hexToRgb(
|
||||
global.current.value.colors.primary
|
||||
)}`"
|
||||
>
|
||||
<RouterView />
|
||||
<TxDialog/>
|
||||
</VApp>
|
||||
</VLocaleProvider>
|
||||
<!-- ℹ️ This is required to set the background color of active nav link based on currently active global theme's primary -->
|
||||
<VApp
|
||||
:style="`--v-global-theme-primary: ${hexToRgb(
|
||||
global.current.value.colors.primary
|
||||
)}`"
|
||||
>
|
||||
<RouterView />
|
||||
<TxDialog />
|
||||
</VApp>
|
||||
</template>
|
||||
|
0
src/components/AccountItem.vue
Normal file
0
src/components/AccountItem.vue
Normal file
@ -1,55 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import { controlledComputed } from '@vueuse/shared';
|
||||
|
||||
interface Props {
|
||||
title: string;
|
||||
color?: string;
|
||||
icon: string;
|
||||
stats: number;
|
||||
change?: number;
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
color: 'primary',
|
||||
});
|
||||
|
||||
const isPositive = controlledComputed(
|
||||
() => props.change,
|
||||
() => Math.sign(props.change || 0) === 1
|
||||
);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<VCard>
|
||||
<VCardText class="d-flex align-center">
|
||||
<VAvatar
|
||||
size="40"
|
||||
rounded
|
||||
:color="props.color"
|
||||
variant="tonal"
|
||||
class="me-4"
|
||||
>
|
||||
<VIcon :icon="props.icon" size="24" />
|
||||
</VAvatar>
|
||||
|
||||
<div class="d-flex flex-column">
|
||||
<div class="d-flex align-center flex-wrap">
|
||||
<h6 class="text-h6">
|
||||
{{ props.stats }}
|
||||
</h6>
|
||||
<div
|
||||
v-if="props.change"
|
||||
:class="`${isPositive ? 'text-success' : 'text-error'}`"
|
||||
>
|
||||
<VIcon
|
||||
size="24"
|
||||
:icon="isPositive ? 'mdi-chevron-up' : 'mdi-chevron-down'"
|
||||
/>
|
||||
<span class="text-caption">{{ Math.abs(props.change) }}%</span>
|
||||
</div>
|
||||
</div>
|
||||
<span class="text-caption">{{ props.title }}</span>
|
||||
</div>
|
||||
</VCardText>
|
||||
</VCard>
|
||||
</template>
|
@ -1,4 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { Icon } from '@iconify/vue';
|
||||
|
||||
interface Props {
|
||||
title: string;
|
||||
color?: string;
|
||||
@ -19,40 +21,40 @@ const isPositive = controlledComputed(
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<VCard class="h-full flex-col content-between">
|
||||
<VCardText class="d-flex align-center justify-between">
|
||||
<VAvatar
|
||||
<div class="bg-base-100 shadow rounded p-4">
|
||||
<div class="flex items-center justify-between">
|
||||
<div
|
||||
v-if="props.icon"
|
||||
rounded
|
||||
size="38"
|
||||
variant="tonal"
|
||||
:color="props.color"
|
||||
class="relative w-9 h-9 rounded overflow-hidden flex items-center justify-center"
|
||||
>
|
||||
<VIcon :icon="props.icon" size="24" />
|
||||
</VAvatar>
|
||||
<Icon :class="[`text-${props?.color}`]" :icon="props.icon" size="32" />
|
||||
<div
|
||||
class="absolute top-0 left-0 bottom-0 right-0 opacity-20"
|
||||
:class="[`bg-${props?.color}`]"
|
||||
></div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="props.change"
|
||||
:class="isPositive ? 'text-success' : 'text-error'"
|
||||
class="d-flex align-center text-sm font-weight-medium mt-n4"
|
||||
class="flex items-center text-sm font-semibold"
|
||||
>
|
||||
<span>{{ isPositive ? `+${props.change}` : props.change }}%</span>
|
||||
|
||||
<VIcon :icon="isPositive ? 'mdi-chevron-up' : 'mdi-chevron-down'" />
|
||||
<Icon :icon="isPositive ? 'mdi-chevron-up' : 'mdi-chevron-down'" />
|
||||
</div>
|
||||
</VCardText>
|
||||
</div>
|
||||
|
||||
<VCardText class="d-flex flex-col">
|
||||
<h6 class="text-h6 me-2 mt-2 mb-1">
|
||||
<div class="">
|
||||
<h6 class="text-lg font-semibold mt-2 mb-1">
|
||||
{{ props.stats }}
|
||||
</h6>
|
||||
<p class="text-sm">
|
||||
{{ props.title }}
|
||||
</p>
|
||||
|
||||
<VChip v-if="props.subtitle" size="x-small" class="font-weight-medium">
|
||||
<div v-if="props.subtitle" size="x-small" class="font-semibold">
|
||||
<span class="text-truncate">{{ props.subtitle }}</span>
|
||||
</VChip>
|
||||
</VCardText>
|
||||
</VCard>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -1,64 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
interface Props {
|
||||
title: string;
|
||||
subtitle: string;
|
||||
stats: string;
|
||||
change: number;
|
||||
image: string;
|
||||
imgWidth: number;
|
||||
color?: string;
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
color: 'primary',
|
||||
});
|
||||
|
||||
const isPositive = controlledComputed(
|
||||
() => props.change,
|
||||
() => Math.sign(props.change) === 1
|
||||
);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<VCard>
|
||||
<VCardText>
|
||||
<h6 class="text-base font-weight-semibold mb-2">
|
||||
{{ props.title }}
|
||||
</h6>
|
||||
<VChip
|
||||
v-if="props.subtitle"
|
||||
size="x-small"
|
||||
:color="props.color"
|
||||
class="mb-5"
|
||||
>
|
||||
{{ props.subtitle }}
|
||||
</VChip>
|
||||
|
||||
<div class="d-flex align-center flex-wrap">
|
||||
<h5 class="text-h5 me-2">
|
||||
{{ props.stats }}
|
||||
</h5>
|
||||
<span
|
||||
class="text-caption"
|
||||
:class="isPositive ? 'text-success' : 'text-error'"
|
||||
>
|
||||
{{ isPositive ? `+${props.change}` : props.change }}%
|
||||
</span>
|
||||
</div>
|
||||
</VCardText>
|
||||
|
||||
<VSpacer />
|
||||
|
||||
<div class="illustrator-img">
|
||||
<VImg v-if="props.image" :src="props.image" :width="props.imgWidth" />
|
||||
</div>
|
||||
</VCard>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
.illustrator-img {
|
||||
position: absolute;
|
||||
inset-block-end: 0;
|
||||
inset-inline-end: 5%;
|
||||
}
|
||||
</style>
|
@ -1,5 +1,5 @@
|
||||
<script lang="ts" setup>
|
||||
import { getLogo, useDashboard } from '@/stores/useDashboard';
|
||||
import { useDashboard } from '@/stores/useDashboard';
|
||||
import { computed } from 'vue';
|
||||
import { Icon } from '@iconify/vue';
|
||||
|
||||
|
@ -1,12 +1,12 @@
|
||||
<script lang="ts" setup>
|
||||
import { useTxDialog } from '@/stores'
|
||||
const store = useTxDialog()
|
||||
import { useTxDialog } from '@/stores';
|
||||
const store = useTxDialog();
|
||||
</script>
|
||||
<template>
|
||||
<ping-tx-dialog
|
||||
:type="store.type"
|
||||
:sender="store.sender"
|
||||
:endpoint="store.endpoint"
|
||||
:params="store.params"
|
||||
></ping-tx-dialog>
|
||||
</template>
|
||||
<ping-tx-dialog
|
||||
:type="store.type"
|
||||
:sender="store.sender"
|
||||
:endpoint="store.endpoint"
|
||||
:params="store.params"
|
||||
></ping-tx-dialog>
|
||||
</template>
|
||||
|
@ -23,15 +23,16 @@ const bars = computed(() => {
|
||||
});
|
||||
</script>
|
||||
<template>
|
||||
<div class="d-flex justify-evenly">
|
||||
<span v-for="(b, i) in bars" :key="i" :class="b.color" style="width: 1.5%"
|
||||
>
|
||||
<v-tooltip
|
||||
v-if="Number(b.height) > 0"
|
||||
activator="parent"
|
||||
location="top"
|
||||
>{{ b.height }}</v-tooltip
|
||||
>
|
||||
</span>
|
||||
<div class="d-flex items-center justify-evenly">
|
||||
<div class="cursor-default" v-for="(item, index) in bars" :key="index">
|
||||
<div class="tooltip" :data-tip="item.height">
|
||||
<span
|
||||
:class="item.color"
|
||||
class="rounded"
|
||||
style="width: 1.5%"
|
||||
>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -136,35 +136,27 @@ const chartConfig = computed(() => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<VCard
|
||||
title="Commission Rate"
|
||||
:subtitle="`Updated at ${format.toDay(
|
||||
props.commission?.update_time,
|
||||
'short'
|
||||
)}`"
|
||||
>
|
||||
<VCardText>
|
||||
<VueApexCharts
|
||||
type="donut"
|
||||
height="257"
|
||||
:options="chartConfig"
|
||||
:series="series"
|
||||
/>
|
||||
|
||||
<div class="d-flex align-center justify-center flex-wrap mx-2 gap-x-6">
|
||||
<div class="d-flex align-center gap-2">
|
||||
<VBadge dot color="success" />
|
||||
<span class="mt-1 text-caption">Rate:{{ rate }}%</span>
|
||||
<div class="bg-base-100 rounded shadow p-4">
|
||||
<div class="text-lg text-main font-semibold mb-1">Commission Rate</div>
|
||||
<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" />
|
||||
<div>
|
||||
<div class="flex items-center justify-center flex-wrap gap-x-3">
|
||||
<div class="flex items-center gap-x-2">
|
||||
<div class="bg-success w-[6px] h-[6px] rounded-full"></div>
|
||||
<span class="text-caption">Rate:{{ rate }}%</span>
|
||||
</div>
|
||||
<div class="d-flex align-center gap-2">
|
||||
<VBadge dot color="success" style="opacity: 0.2" />
|
||||
<span class="mt-1 text-caption">24h: ±{{ change }}%</span>
|
||||
<div class="flex items-center gap-x-2">
|
||||
<div class="bg-success w-[6px] h-[6px] rounded-full opacity-60"></div>
|
||||
<span class="text-caption">24h: ±{{ change }}%</span>
|
||||
</div>
|
||||
<div class="d-flex align-center gap-2">
|
||||
<VBadge dot color="secondary" />
|
||||
<span class="mt-1 text-caption">Max:{{ max }}%</span>
|
||||
<div class="flex items-center gap-x-2">
|
||||
<div class="bg-secondary w-[6px] h-[6px] rounded-full"></div>
|
||||
<span class="text-caption">Max:{{ max }}%</span>
|
||||
</div>
|
||||
</div>
|
||||
</VCardText>
|
||||
</VCard>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -1,9 +1,4 @@
|
||||
<script lang="ts" setup>
|
||||
import { toBase64 } from '@cosmjs/encoding';
|
||||
import type { PropType } from 'vue';
|
||||
import { computed } from '@vue/reactivity';
|
||||
import DynamicComponentVue from './DynamicComponent.vue';
|
||||
import { select } from './index';
|
||||
import ArrayBytesElement from './ArrayBytesElement.vue';
|
||||
import ArrayObjectElement from './ArrayObjectElement.vue';
|
||||
import TextElement from './TextElement.vue';
|
||||
|
@ -1,5 +1,4 @@
|
||||
<script lang="ts" setup>
|
||||
import DynamicComponent from './DynamicComponent.vue';
|
||||
import { select } from './index';
|
||||
|
||||
const props = defineProps(['value']);
|
||||
|
@ -1,7 +1,6 @@
|
||||
<script lang="ts" setup>
|
||||
import DynamicComponent from './DynamicComponent.vue';
|
||||
import { select } from './index';
|
||||
import { ref} from 'vue'
|
||||
import { ref } from 'vue';
|
||||
const props = defineProps(['value']);
|
||||
const tab = ref(Object.keys(props.value)[0] || '');
|
||||
|
||||
@ -12,16 +11,19 @@ const changeTab = (val: string) => {
|
||||
<template>
|
||||
<div>
|
||||
<div class="tabs">
|
||||
<a class="tab tab-bordered text-gray-400 uppercase"
|
||||
v-for="(item, index) of value" :value="index"
|
||||
:class="{ 'tab-active':tab === String(index) }"
|
||||
<a
|
||||
class="tab tab-bordered text-gray-400 uppercase"
|
||||
v-for="(item, index) of value"
|
||||
:value="index"
|
||||
:class="{ 'tab-active': tab === String(index) }"
|
||||
@click="changeTab(String(index))"
|
||||
>{{ index }}</a>
|
||||
>{{ index }}</a
|
||||
>
|
||||
</div>
|
||||
<div class="min-h-[25px] mt-4">
|
||||
<div v-for="(v, k) of value" :value="k">
|
||||
<DynamicComponent :value="v" v-show="tab === String(k)"/>
|
||||
</div>
|
||||
<div v-for="(v, k) of value" :value="k">
|
||||
<DynamicComponent :value="v" v-show="tab === String(k)" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -1,5 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { useBlockchain } from '@/stores/useBlockchain';
|
||||
import { Icon } from '@iconify/vue';
|
||||
import { computed } from '@vue/reactivity';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useRoute } from 'vue-router';
|
||||
@ -20,10 +21,10 @@ const items = computed(() => [
|
||||
<template>
|
||||
<div class="d-flex flex-rows align-center">
|
||||
<span class="text-h5 mr-3">{{ moduleName }}</span>
|
||||
<v-icon icon="mdi-dots-vertical" />
|
||||
<Icon icon="mdi-dots-vertical"/>
|
||||
<VBreadcrumbs :items="items">
|
||||
<template v-slot:divider>
|
||||
<v-icon icon="mdi-chevron-right"></v-icon>
|
||||
<Icon icon="mdi-chevron-right"/>
|
||||
</template>
|
||||
</VBreadcrumbs>
|
||||
</div>
|
||||
|
@ -16,7 +16,7 @@ chainStore.$subscribe((m, s) => {
|
||||
<div tabindex="0" class="p-1 relative mr-3 cursor-pointer">
|
||||
<img v-lazy="chainStore.logo" class="w-9 h-9 rounded-full" />
|
||||
<div
|
||||
class="w-2 h-2 rounded-full bg-yes absolute right-0 bottom-0"
|
||||
class="w-2 h-2 rounded-full bg-yes absolute right-0 bottom-0 shadow"
|
||||
></div>
|
||||
</div>
|
||||
<div
|
||||
|
@ -4,20 +4,15 @@ import { ref } from 'vue';
|
||||
import { useThemeConfig } from '@/plugins/vuetify/@core/composable/useThemeConfig';
|
||||
|
||||
// Components
|
||||
// import Footer from '@/layouts/components/Footer.vue';
|
||||
import newFooter from '@/layouts/components/newFooter.vue';
|
||||
import newFooter from '@/layouts/components/NavFooter.vue';
|
||||
import NavbarThemeSwitcher from '@/layouts/components/NavbarThemeSwitcher.vue';
|
||||
import UserProfile from '@/layouts/components/ChainProfile.vue';
|
||||
|
||||
import { useDashboard } from '@/stores/useDashboard';
|
||||
|
||||
// @layouts plugin
|
||||
import NavBarI18n from './NavBarI18n.vue';
|
||||
import NavSearchBar from './NavSearchBar.vue';
|
||||
import NavBarNotifications from './NavBarNotifications.vue';
|
||||
import NavBarWallet from './NavBarWallet.vue';
|
||||
import TheCustomizer from '@/plugins/vuetify/@core/components/TheCustomizer.vue';
|
||||
import Breadcrumbs from './Breadcrumbs.vue';
|
||||
import { useBlockchain } from '@/stores';
|
||||
|
||||
const { appRouteTransition } = useThemeConfig();
|
||||
@ -44,7 +39,9 @@ const sidebarShow = ref(false);
|
||||
>
|
||||
<div class="flex items-center pl-4 py-4 mb-1">
|
||||
<img class="w-10 h-10" src="../../assets/logo.svg" />
|
||||
<h1 class="flex-1 ml-3 text-2xl font-semibold dark:text-white">Ping.pub</h1>
|
||||
<h1 class="flex-1 ml-3 text-2xl font-semibold dark:text-white">
|
||||
Ping.pub
|
||||
</h1>
|
||||
<div class="pr-4 cursor-pointer xl:hidden" @click="sidebarShow = false">
|
||||
<Icon icon="mdi-close" class="text-3xl" />
|
||||
</div>
|
||||
@ -178,7 +175,8 @@ const sidebarShow = ref(false);
|
||||
<NavBarNotifications class="hidden md:inline-block" />
|
||||
<NavBarI18n class="hidden md:inline-block" />
|
||||
<NavbarThemeSwitcher class="hidden md:inline-block" />
|
||||
<NavBarWallet class="md:inline-block" />
|
||||
|
||||
<NavBarWallet class="block truncate md:inline-block text-xs md:text-sm" />
|
||||
</div>
|
||||
|
||||
<!-- 👉 Pages -->
|
||||
|
@ -1,11 +1,10 @@
|
||||
<script lang="ts" setup>
|
||||
import NavBarI18n from '@core/components/I18n.vue';
|
||||
import { useThemeConfig } from '@core/composable/useThemeConfig';
|
||||
import type { I18nLanguage } from '@layouts/types';
|
||||
|
||||
const { isAppRtl } = useThemeConfig();
|
||||
|
||||
const i18nCompLanguages: I18nLanguage[] = [
|
||||
const i18nCompLanguages: Array<{ label: string; i18nLang: string }> = [
|
||||
{
|
||||
label: 'English',
|
||||
i18nLang: 'en',
|
||||
@ -14,10 +13,6 @@ const i18nCompLanguages: I18nLanguage[] = [
|
||||
label: '中文',
|
||||
i18nLang: 'cn',
|
||||
},
|
||||
{
|
||||
label: 'Arabic',
|
||||
i18nLang: 'ar',
|
||||
},
|
||||
];
|
||||
|
||||
const handleLangChange = (lang: string) => {
|
||||
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<footer class="footer items-center p-4 text-base mb-4">
|
||||
<footer class="footer items-center p-4 text-sm mb-4">
|
||||
<div class="items-center grid-flow-col">
|
||||
©
|
||||
{{ new Date().getFullYear() }}
|
@ -1,7 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import type { ThemeSwitcherTheme } from '@layouts/types';
|
||||
import NewThemeSwitcher from '@/components/ThemeSwitcher.vue';
|
||||
const themes: ThemeSwitcherTheme[] = [
|
||||
const themes: Array<{ name: string; icon: string }> = [
|
||||
{
|
||||
name: 'system',
|
||||
icon: 'mdi-laptop',
|
||||
|
@ -1,10 +1,6 @@
|
||||
<script lang="ts" setup>
|
||||
import { useSkins } from '@core/composable/useSkins';
|
||||
import { useThemeConfig } from '@core/composable/useThemeConfig';
|
||||
|
||||
const DefaultLayout = defineAsyncComponent(
|
||||
() => import('./components/DefaultLayout.vue')
|
||||
);
|
||||
import DefaultLayout from './components/DefaultLayout.vue';
|
||||
|
||||
const { layoutAttrs, injectSkinClasses } = useSkins();
|
||||
|
||||
@ -14,8 +10,3 @@ injectSkinClasses();
|
||||
<template>
|
||||
<DefaultLayout v-bind="layoutAttrs" />
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
// As we are using `layouts` plugin we need its styles to be imported
|
||||
@use '@layouts/styles/default-layout';
|
||||
</style>
|
||||
|
@ -1,8 +1,14 @@
|
||||
<script lang="ts" setup>
|
||||
import { useBlockchain, useFormatter, useStakingStore, useTxDialog } from '@/stores';
|
||||
import {
|
||||
useBlockchain,
|
||||
useFormatter,
|
||||
useStakingStore,
|
||||
useTxDialog,
|
||||
} from '@/stores';
|
||||
import DynamicComponent from '@/components/dynamic/DynamicComponent.vue';
|
||||
import DonutChart from '@/components/charts/DonutChart.vue';
|
||||
import { computed, ref } from '@vue/reactivity';
|
||||
import { Icon } from '@iconify/vue';
|
||||
import 'vue-json-pretty/lib/styles.css';
|
||||
import type {
|
||||
AuthAccount,
|
||||
@ -85,24 +91,168 @@ loadAccount(props.address);
|
||||
</script>
|
||||
<template>
|
||||
<div v-if="account">
|
||||
<VCard>
|
||||
<VList>
|
||||
<VListItem>
|
||||
<template #prepend>
|
||||
<VAvatar rounded variant="tonal" size="45" color="primary">
|
||||
<VIcon icon="mdi-qrcode" />
|
||||
</VAvatar>
|
||||
</template>
|
||||
<!-- address -->
|
||||
<div class="bg-base-100 px-4 pt-3 pb-4 rounded mb-4 shadow">
|
||||
<div class="d-flex items-center">
|
||||
<!-- img -->
|
||||
<div class="inline-flex relative w-11 h-11 rounded-md">
|
||||
<div
|
||||
class="w-11 h-11 absolute rounded-md opacity-10 bg-primary"
|
||||
></div>
|
||||
<div
|
||||
class="w-full inline-flex items-center align-middle flex-none justify-center"
|
||||
>
|
||||
<Icon
|
||||
icon="mdi-qrcode"
|
||||
class="text-primary"
|
||||
style="width: 27px; height: 27px"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<!-- content -->
|
||||
<div class="flex flex-1 flex-col truncate pl-4">
|
||||
<h2 class="text-sm card-title">Address:</h2>
|
||||
<span class="text-xs truncate"> {{ address }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<VListItemTitle class="text-sm font-weight-semibold">
|
||||
Address:
|
||||
</VListItemTitle>
|
||||
<VListItemSubtitle class="text-xs">
|
||||
{{ address }}
|
||||
</VListItemSubtitle>
|
||||
</VListItem>
|
||||
</VList>
|
||||
</VCard>
|
||||
<!-- Assets -->
|
||||
<div class="bg-base-100 px-4 pt-3 pb-4 rounded mb-4 shadow">
|
||||
<h2 class="card-title mb-4">Assets</h2>
|
||||
<div class="grid md:grid-cols-3">
|
||||
<div class="md:col-span-1">
|
||||
<DonutChart :series="totalAmountByCategory" :labels="labels" />
|
||||
</div>
|
||||
<div class="mt-4 md:col-span-2 md:mt-0 md:ml-4">
|
||||
<!-- button -->
|
||||
<div class="d-flex justify-end mb-4">
|
||||
<label
|
||||
for="send"
|
||||
class="btn btn-primary btn-sm mr-2"
|
||||
@click="dialog.open('send', {})"
|
||||
>Send</label
|
||||
>
|
||||
<label
|
||||
for="transfer"
|
||||
class="btn btn-primary btn-sm"
|
||||
@click="
|
||||
dialog.open('transfer', {
|
||||
chain_name: blockchain.current?.prettyName,
|
||||
})
|
||||
"
|
||||
>transfer</label
|
||||
>
|
||||
</div>
|
||||
<!-- -->
|
||||
<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>
|
||||
<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>
|
||||
|
||||
<div class="flex items-center px-4">
|
||||
<div
|
||||
class="w-9 h-9 rounded overflow-hidden flex items-center justify-center relative mr-4"
|
||||
>
|
||||
<Icon
|
||||
icon="mdi-account-arrow-right"
|
||||
class="text-error"
|
||||
size="20"
|
||||
/>
|
||||
<div
|
||||
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">
|
||||
{{
|
||||
format.formatToken({
|
||||
amount: String(unbondingTotal),
|
||||
denom: stakingStore.params.bond_denom,
|
||||
})
|
||||
}}
|
||||
</div>
|
||||
<div class="text-sm">≈${{ 0 }}</div>
|
||||
</div>
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="divider"></div>
|
||||
{{ totalAmount }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<VCard class="mt-5">
|
||||
<VCardTitle>Assets</VCardTitle>
|
||||
@ -114,8 +264,22 @@ loadAccount(props.address);
|
||||
<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>
|
||||
<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>
|
||||
@ -130,9 +294,14 @@ loadAccount(props.address);
|
||||
≈${{ 0 }}
|
||||
</VListItemSubtitle>
|
||||
<template #append>
|
||||
<VChip color="primary">{{
|
||||
format.calculatePercent(v.amount, totalAmount)
|
||||
}}</VChip>
|
||||
<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">
|
||||
@ -149,9 +318,14 @@ loadAccount(props.address);
|
||||
≈${{ 0 }}
|
||||
</VListItemSubtitle>
|
||||
<template #append>
|
||||
<VChip color="primary">{{
|
||||
format.calculatePercent(v.balance.amount, totalAmount)
|
||||
}}</VChip>
|
||||
<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">
|
||||
@ -168,9 +342,14 @@ loadAccount(props.address);
|
||||
≈${{ 0 }}
|
||||
</VListItemSubtitle>
|
||||
<template #append>
|
||||
<VChip color="primary">{{
|
||||
format.calculatePercent(v.amount, totalAmount)
|
||||
}}</VChip>
|
||||
<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>
|
||||
|
||||
@ -193,9 +372,14 @@ loadAccount(props.address);
|
||||
≈${{ 0 }}
|
||||
</VListItemSubtitle>
|
||||
<template #append>
|
||||
<VChip color="primary">{{
|
||||
format.calculatePercent(unbondingTotal, totalAmount)
|
||||
}}</VChip>
|
||||
<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>
|
||||
@ -206,25 +390,34 @@ loadAccount(props.address);
|
||||
</VCardItem>
|
||||
</VCard>
|
||||
|
||||
<VCard class="my-5">
|
||||
<VCardItem>
|
||||
<VCardTitle>
|
||||
Delegations
|
||||
<div>
|
||||
<label for="delegate" class="btn btn-primary float-right btn-sm" @click="dialog.open('delegate', {})">Delegate</label>
|
||||
<label for="withdraw" class="btn btn-primary float-right btn-sm" @click="dialog.open('withdraw', {})">Withdraw</label>
|
||||
</div>
|
||||
</VCardTitle>
|
||||
<VTable>
|
||||
<!-- 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">
|
||||
<label
|
||||
for="delegate"
|
||||
class="btn btn-primary btn-sm mr-2"
|
||||
@click="dialog.open('delegate', {})"
|
||||
>Delegate</label
|
||||
>
|
||||
<label
|
||||
for="withdraw"
|
||||
class="btn btn-primary btn-sm"
|
||||
@click="dialog.open('withdraw', {})"
|
||||
>Withdraw</label
|
||||
>
|
||||
</div>
|
||||
<div class="overdflow-x-auto">
|
||||
<table class="table w-full">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Validator</th>
|
||||
<th style="position: relative">Validator</th>
|
||||
<th>Delegation</th>
|
||||
<th>Rewards</th>
|
||||
<th>Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tbody class="text-sm">
|
||||
<tr v-for="v in delegations">
|
||||
<td class="text-caption text-primary">
|
||||
<RouterLink
|
||||
@ -246,28 +439,62 @@ loadAccount(props.address);
|
||||
}}
|
||||
</td>
|
||||
<td>
|
||||
<label for="delegate" class="btn btn-primary float-right btn-sm" @click="dialog.open('delegate', {validator_address: v.delegation.validator_address})">delegate</label>
|
||||
<label for="redelegate" class="btn btn-primary float-right btn-sm" @click="dialog.open('redelegate', {validator_address: v.delegation.validator_address})">Redelegate</label>
|
||||
<label for="unbond" class="btn btn-primary float-right btn-sm" @click="dialog.open('unbond', {validator_address: v.delegation.validator_address})">Unbond</label>
|
||||
<div class="d-flex justify-end">
|
||||
<label
|
||||
for="delegate"
|
||||
class="btn btn-primary btn-sm mr-2"
|
||||
@click="
|
||||
dialog.open('delegate', {
|
||||
validator_address: v.delegation.validator_address,
|
||||
})
|
||||
"
|
||||
>delegate</label
|
||||
>
|
||||
<label
|
||||
for="redelegate"
|
||||
class="btn btn-primary btn-sm mr-2"
|
||||
@click="
|
||||
dialog.open('redelegate', {
|
||||
validator_address: v.delegation.validator_address,
|
||||
})
|
||||
"
|
||||
>Redelegate</label
|
||||
>
|
||||
<label
|
||||
for="unbond"
|
||||
class="btn btn-primary btn-sm"
|
||||
@click="
|
||||
dialog.open('unbond', {
|
||||
validator_address: v.delegation.validator_address,
|
||||
})
|
||||
"
|
||||
>Unbond</label
|
||||
>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</VTable>
|
||||
</VCardItem>
|
||||
</VCard>
|
||||
<VCard class="my-5" v-if="unbonding && unbonding.length > 0">
|
||||
<VCardItem>
|
||||
<VCardTitle>Unbonding Delegations</VCardTitle>
|
||||
<VTable>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Unbonding Delegations -->
|
||||
<div
|
||||
class="bg-base-100 px-4 pt-3 pb-4 rounded mb-4 shadow"
|
||||
v-if="unbonding && unbonding.length > 0"
|
||||
>
|
||||
<h2 class="card-title mb-4">Unbonding Delegations</h2>
|
||||
<div class="overflow-x-auto">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Creation Height</th>
|
||||
<th style="position: relative">Creation Height</th>
|
||||
<th>Initial Balance</th>
|
||||
<th>Balance</th>
|
||||
<th>Completion Time</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tbody class="text-sm">
|
||||
<div v-for="v in unbonding">
|
||||
<tr>
|
||||
<td class="text-caption text-primary">
|
||||
@ -309,22 +536,24 @@ loadAccount(props.address);
|
||||
</tr>
|
||||
</div>
|
||||
</tbody>
|
||||
</VTable>
|
||||
</VCardItem>
|
||||
</VCard>
|
||||
<VCard class="my-5">
|
||||
<VCardItem>
|
||||
<VCardTitle>Transactions</VCardTitle>
|
||||
<VTable>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Transactions -->
|
||||
<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">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Height</th>
|
||||
<th style="position: relative">Height</th>
|
||||
<th>Hash</th>
|
||||
<th>Messages</th>
|
||||
<th>Time</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tbody class="text-sm">
|
||||
<tr v-for="v in txs">
|
||||
<td class="text-sm text-primary">
|
||||
<RouterLink :to="`/${chain}/block/${v.height}`">{{
|
||||
@ -346,15 +575,15 @@ loadAccount(props.address);
|
||||
<td>{{ format.toDay(v.timestamp, 'from') }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</VTable>
|
||||
</VCardItem>
|
||||
</VCard>
|
||||
<VCard>
|
||||
<VCardItem>
|
||||
<VCardTitle>Account</VCardTitle>
|
||||
<DynamicComponent :value="account" />
|
||||
</VCardItem>
|
||||
</VCard>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Account -->
|
||||
<div class="bg-base-100 px-4 pt-3 pb-4 rounded mb-4 shadow">
|
||||
<h2 class="card-title mb-4">Account</h2>
|
||||
<DynamicComponent :value="account" />
|
||||
</div>
|
||||
</div>
|
||||
<div v-else>Account does not exists on chain</div>
|
||||
</template>
|
||||
|
@ -1,5 +1,4 @@
|
||||
<script lang="ts" setup>
|
||||
import { fromHex } from '@cosmjs/encoding';
|
||||
import { useWasmStore } from '../WasmStore';
|
||||
import { ref } from 'vue';
|
||||
import type {
|
||||
@ -8,7 +7,6 @@ import type {
|
||||
PaginabledContracts,
|
||||
} from '../types';
|
||||
import DynamicComponent from '@/components/dynamic/DynamicComponent.vue';
|
||||
import type CustomRadiosVue from '@/plugins/vuetify/@core/components/CustomRadios.vue';
|
||||
import type { CustomInputContent } from '@/plugins/vuetify/@core/types';
|
||||
import { useFormatter } from '@/stores';
|
||||
|
||||
@ -94,12 +92,14 @@ const result = ref('');
|
||||
<template>
|
||||
<div>
|
||||
<div class="bg-base-100 px-4 pt-3 pb-4 rounded mb-4 shadow">
|
||||
<h2 class="card-title truncate w-full">Contract List of Code: {{ props.code_id }}</h2>
|
||||
<h2 class="card-title truncate w-full">
|
||||
Contract List of Code: {{ props.code_id }}
|
||||
</h2>
|
||||
<div class="overflow-x-auto">
|
||||
<table class="table w-full mt-4">
|
||||
<table class="table w-full mt-4">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="position: relative;">Contract List</th>
|
||||
<th style="position: relative">Contract List</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@ -110,22 +110,28 @@ const result = ref('');
|
||||
<button
|
||||
class="btn btn-primary btn-sm text-xs mr-2"
|
||||
@click="showInfo(v)"
|
||||
>contract</button>
|
||||
>
|
||||
contract
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-primary btn-sm text-xs mr-2"
|
||||
@click="showState(v)"
|
||||
>States</button>
|
||||
>
|
||||
States
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-primary btn-sm text-xs"
|
||||
@click="showQuery(v)"
|
||||
>Query</button>
|
||||
>
|
||||
Query
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<v-dialog v-model="infoDialog" width="auto">
|
||||
<v-card>
|
||||
<VCardTitle>Contract Detail</VCardTitle>
|
||||
@ -160,7 +166,7 @@ const result = ref('');
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
|
||||
|
||||
<v-dialog v-model="queryDialog" width="auto">
|
||||
<v-card>
|
||||
<VCardTitle>Query Contract</VCardTitle>
|
||||
|
@ -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">Code Id</th>
|
||||
<th>Code Hash</th>
|
||||
<th>Creator</th>
|
||||
<th>Permissions</th>
|
||||
|
@ -1,12 +1,6 @@
|
||||
<script lang="ts" setup>
|
||||
import DynamicComponent from '@/components/dynamic/DynamicComponent.vue';
|
||||
import { useBaseStore, useBlockchain, useFormatter } from '@/stores';
|
||||
import type {
|
||||
ClientStateWithProof,
|
||||
Connection,
|
||||
ClientState,
|
||||
Channel,
|
||||
} from '@/types';
|
||||
import { useBaseStore, useBlockchain } from '@/stores';
|
||||
import type { Connection, ClientState, Channel } from '@/types';
|
||||
import { onMounted } from 'vue';
|
||||
import { ref } from 'vue';
|
||||
|
||||
@ -136,16 +130,16 @@ function color(v: string) {
|
||||
<td>{{ v.version }}</td>
|
||||
<td>{{ v.ordering }}</td>
|
||||
<td>
|
||||
<div
|
||||
class="text-xs truncate relative py-2 px-4 rounded-full w-fit"
|
||||
:class="`text-${color(v.state)}`"
|
||||
>
|
||||
<span
|
||||
class="inset-x-0 inset-y-0 opacity-10 absolute"
|
||||
:class="`bg-${color(v.state)}`"
|
||||
></span>
|
||||
{{ v.state }}
|
||||
</div>
|
||||
<div
|
||||
class="text-xs truncate relative py-2 px-4 rounded-full w-fit"
|
||||
:class="`text-${color(v.state)}`"
|
||||
>
|
||||
<span
|
||||
class="inset-x-0 inset-y-0 opacity-10 absolute"
|
||||
:class="`bg-${color(v.state)}`"
|
||||
></span>
|
||||
{{ v.state }}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
@ -48,11 +48,11 @@ function color(v: string) {
|
||||
</td>
|
||||
<td>{{ v.delay_period }}</td>
|
||||
<td>
|
||||
<div
|
||||
<div
|
||||
class="text-xs truncate relative py-2 px-4 rounded-full w-fit"
|
||||
:class="`text-${color(v.state)}`"
|
||||
>
|
||||
<span
|
||||
<span
|
||||
class="inset-x-0 inset-y-0 opacity-10 absolute"
|
||||
:class="`bg-${color(v.state)}`"
|
||||
></span>
|
||||
|
@ -135,29 +135,18 @@ onMounted(() => {
|
||||
</script>
|
||||
<template>
|
||||
<div>
|
||||
<div style="border-width:1px" class="bg-base-100 px-4 pt-3 pb-4 rounded shadow border-indigo-500">
|
||||
<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-1">
|
||||
<div class="flex">
|
||||
<!-- avator -->
|
||||
<!-- <VAvatar
|
||||
icon="mdi-help-circle-outline"
|
||||
:image="avatars[identity]"
|
||||
size="90"
|
||||
rounded
|
||||
variant="outlined"
|
||||
color="secondary"
|
||||
/> -->
|
||||
<div
|
||||
class="avatar mr-4 relative w-24 rounded-lg overflow-hidden"
|
||||
>
|
||||
<div
|
||||
class="w-24 rounded-lg absolute opacity-10"
|
||||
></div>
|
||||
<div class="avatar mr-4 relative w-24 rounded-lg overflow-hidden">
|
||||
<div class="w-24 rounded-lg absolute opacity-10"></div>
|
||||
<div class="w-24 rounded-lg">
|
||||
<img
|
||||
v-if="avatars[identity] !== 'undefined'"
|
||||
:src="`https://s3.amazonaws.com/keybase_processed_uploads/${avatars[identity]}`"
|
||||
v-lazy="
|
||||
`https://s3.amazonaws.com/keybase_processed_uploads/${avatars[identity]}`
|
||||
"
|
||||
class="object-contain"
|
||||
/>
|
||||
<Icon
|
||||
@ -172,212 +161,226 @@ onMounted(() => {
|
||||
<div class="text-sm mb-2">
|
||||
{{ v.description?.identity || '-' }}
|
||||
</div>
|
||||
<label for="delegate" class="btn btn-primary btn-sm w-full" @click="dialog.open('delegate', {validator_address: v.operator_address})">Delegate</label>
|
||||
<label
|
||||
for="delegate"
|
||||
class="btn btn-primary btn-sm w-full"
|
||||
@click="
|
||||
dialog.open('delegate', {
|
||||
validator_address: v.operator_address,
|
||||
})
|
||||
"
|
||||
>Delegate</label
|
||||
>
|
||||
</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>
|
||||
<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">
|
||||
<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>
|
||||
<VListItem prepend-icon="mdi-shield-account-outline">
|
||||
<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>
|
||||
<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">
|
||||
<h4>
|
||||
{{
|
||||
format.formatToken2({
|
||||
amount: v.tokens,
|
||||
denom: staking.params.bond_denom,
|
||||
})
|
||||
}}
|
||||
</h4>
|
||||
<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">
|
||||
<h4>
|
||||
{{ format.formatToken(selfBonded.balance) }} ({{
|
||||
selfRate
|
||||
}})
|
||||
</h4>
|
||||
<span class="text-sm">Self Bonded</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="d-flex">
|
||||
<VAvatar
|
||||
color="secondary"
|
||||
rounded
|
||||
variant="outlined"
|
||||
icon="mdi-account-tie"
|
||||
></VAvatar>
|
||||
<div class="ml-3 d-flex flex-column justify-center">
|
||||
<h4>
|
||||
{{ v.min_self_delegation }} {{ staking.params.bond_denom }}
|
||||
</h4>
|
||||
<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">
|
||||
<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">
|
||||
<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">
|
||||
<h4>{{ format.toDay(v.unbonding_time, 'from') }}</h4>
|
||||
<span class="text-sm">Unbonding Time</span>
|
||||
</div>
|
||||
<div class="d-flex">
|
||||
<VAvatar
|
||||
color="secondary"
|
||||
rounded
|
||||
variant="outlined"
|
||||
icon="mdi-coin"
|
||||
></VAvatar>
|
||||
<div class="ml-3 d-flex flex-column justify-center">
|
||||
<h4>
|
||||
{{
|
||||
format.formatToken2({
|
||||
amount: v.tokens,
|
||||
denom: staking.params.bond_denom,
|
||||
})
|
||||
}}
|
||||
</h4>
|
||||
<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">
|
||||
<h4>
|
||||
{{ format.formatToken(selfBonded.balance) }} ({{ selfRate }})
|
||||
</h4>
|
||||
<span class="text-sm">Self Bonded</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="d-flex">
|
||||
<VAvatar
|
||||
color="secondary"
|
||||
rounded
|
||||
variant="outlined"
|
||||
icon="mdi-account-tie"
|
||||
></VAvatar>
|
||||
<div class="ml-3 d-flex flex-column justify-center">
|
||||
<h4>
|
||||
{{ v.min_self_delegation }} {{ staking.params.bond_denom }}
|
||||
</h4>
|
||||
<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">
|
||||
<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">
|
||||
<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">
|
||||
<h4>{{ format.toDay(v.unbonding_time, 'from') }}</h4>
|
||||
<span class="text-sm">Unbonding Time</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="divider"></div>
|
||||
<div class="text-sm px-4">{{ v.description?.details }}</div>
|
||||
</div>
|
||||
|
||||
<VRow class="mt-3">
|
||||
<VCol md="4" sm="12" class="h-100">
|
||||
<div class="mt-3 grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||
<div class="h-100">
|
||||
<ValidatorCommissionRate
|
||||
:commission="v.commission"
|
||||
></ValidatorCommissionRate>
|
||||
</VCol>
|
||||
<VCol md="4" sm="12">
|
||||
<VCard class="h-100">
|
||||
<VCardTitle>Commissions & Rewards</VCardTitle>
|
||||
<VCardItem class="pt-0 pb-0">
|
||||
</div>
|
||||
<div>
|
||||
<div class="h-100 bg-base-100 rounded shadow">
|
||||
<div class="text-lg font-semibold text-main px-4 pt-4">
|
||||
Commissions & Rewards
|
||||
</div>
|
||||
<div class="px-4 mt-1">
|
||||
<div class="overflow-auto" style="max-height: 280px">
|
||||
<VCardSubtitle>
|
||||
Commissions
|
||||
</VCardSubtitle>
|
||||
<VDivider class="mb-2"></VDivider>
|
||||
<VChip
|
||||
<div class="text-sm mb-2">Commissions</div>
|
||||
<div
|
||||
v-for="(i, k) in commission"
|
||||
:key="`reward-${k}`"
|
||||
color="info"
|
||||
label
|
||||
variant="outlined"
|
||||
class="mr-1 mb-1"
|
||||
class="mr-1 mb-1 badge text-xs"
|
||||
>
|
||||
{{ format.formatToken2(i) }}
|
||||
</VChip>
|
||||
<VCardSubtitle class="mt-2">Outstanding Rewards</VCardSubtitle>
|
||||
<VDivider class="mb-2"></VDivider>
|
||||
<VChip
|
||||
</div>
|
||||
<div class="text-sm mb-2 mt-2">Outstanding Rewards</div>
|
||||
<div
|
||||
v-for="(i, k) in rewards"
|
||||
:key="`reward-${k}`"
|
||||
color="success"
|
||||
label
|
||||
variant="outlined"
|
||||
class="mr-1 mb-1"
|
||||
class="mr-1 mb-1 badge text-xs"
|
||||
>
|
||||
{{ format.formatToken2(i) }}
|
||||
</VChip>
|
||||
</div>
|
||||
</div>
|
||||
<label for="withdraw_commission" class="btn btn-primary mt-2 w-full btn-sm" @click="dialog.open('withdraw_commission', {validator_address: v.operator_address})">Withdraw</label>
|
||||
</VCardItem>
|
||||
</VCard>
|
||||
</VCol>
|
||||
<VCol md="4" sm="12">
|
||||
<VCard title="Addresses" class="h-100">
|
||||
<VList class="pt-0">
|
||||
<VListItem>
|
||||
<VListItemTitle>Account</VListItemTitle>
|
||||
<VListItemSubtitle class="text-caption text-primary"
|
||||
><RouterLink :to="`/${chain}/account/${addresses.account}`">{{
|
||||
addresses.account
|
||||
}}</RouterLink></VListItemSubtitle
|
||||
<label
|
||||
for="withdraw_commission"
|
||||
class="btn btn-primary mt-4 w-full btn-sm"
|
||||
@click="
|
||||
dialog.open('withdraw_commission', {
|
||||
validator_address: v.operator_address,
|
||||
})
|
||||
"
|
||||
>Withdraw</label
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="h-100 bg-base-100 rounded shadow">
|
||||
<div class="px-4 pt-4 mb-2 text-main font-lg font-semibold">
|
||||
Addresses
|
||||
</div>
|
||||
<div class="px-4">
|
||||
<div class="mb-3">
|
||||
<div class="text-sm">Account</div>
|
||||
<RouterLink
|
||||
class="text-xs text-primary"
|
||||
:to="`/${chain}/account/${addresses.account}`"
|
||||
>
|
||||
</VListItem>
|
||||
<VListItem>
|
||||
<VListItemTitle>Operator Address</VListItemTitle>
|
||||
<VListItemSubtitle class="text-caption">{{
|
||||
v.operator_address
|
||||
}}</VListItemSubtitle>
|
||||
</VListItem>
|
||||
<VListItem>
|
||||
<VListItemTitle>Hex Address</VListItemTitle>
|
||||
<VListItemSubtitle class="text-caption">{{
|
||||
addresses.hex
|
||||
}}</VListItemSubtitle>
|
||||
</VListItem>
|
||||
<VListItem>
|
||||
<VListItemTitle>Signer Address</VListItemTitle>
|
||||
<VListItemSubtitle class="text-caption">{{
|
||||
addresses.valCons
|
||||
}}</VListItemSubtitle>
|
||||
</VListItem>
|
||||
</VList>
|
||||
</VCard>
|
||||
</VCol>
|
||||
</VRow>
|
||||
<VCard title="Transactions" class="mt-5">
|
||||
<VCardItem class="pt-0">
|
||||
<VTable>
|
||||
{{ addresses.account }}
|
||||
</RouterLink>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<div class="text-sm">Operator Address</div>
|
||||
<div class="text-xs">
|
||||
{{ v.operator_address }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<div class="text-sm">Hex Address</div>
|
||||
<div class="text-xs">{{ addresses.hex }}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="text-sm">Signer Address</div>
|
||||
<div class="text-xs">{{ addresses.valCons }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-5 bg-base-100 shadow rounded p-4">
|
||||
<div class="text-lg mb-4 font-semibold">Transactions</div>
|
||||
<div class="rounded overflow-auto">
|
||||
<table class="table validatore-table w-full">
|
||||
<thead>
|
||||
<th class="text-left pl-4">Height</th>
|
||||
<th class="text-left pl-4" style="position: relative; z-index: 2">
|
||||
Height
|
||||
</th>
|
||||
<th class="text-left pl-4">Hash</th>
|
||||
<th class="text-left pl-4" width="40%">Messages</th>
|
||||
<th class="text-left pl-4">Time</th>
|
||||
@ -393,24 +396,30 @@ onMounted(() => {
|
||||
{{ item.txhash }}
|
||||
</td>
|
||||
<td>
|
||||
{{ format.messages(item.tx.body.messages) }}
|
||||
<VIcon
|
||||
v-if="item.code === 0"
|
||||
icon="mdi-check"
|
||||
color="success"
|
||||
></VIcon>
|
||||
<VIcon v-else icon="mdi-multiply" color="error"></VIcon>
|
||||
<div class="flex items-center">
|
||||
<span class="mr-2">{{
|
||||
format.messages(item.tx.body.messages)
|
||||
}}</span>
|
||||
<Icon
|
||||
v-if="item.code === 0"
|
||||
icon="mdi-check"
|
||||
class="text-yes"
|
||||
/>
|
||||
<Icon v-else icon="mdi-multiply" class="text-no" />
|
||||
</div>
|
||||
</td>
|
||||
<td width="150">{{ format.toDay(item.timestamp, 'from') }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</VTable>
|
||||
</VCardItem>
|
||||
</VCard>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
.card-list {
|
||||
--v-card-list-gap: 10px;
|
||||
.validatore-table.table :where(th, td) {
|
||||
padding: 0.6rem 1rem;
|
||||
font-size: 14px;
|
||||
}
|
||||
</style>
|
||||
|
@ -1,5 +1,10 @@
|
||||
<script lang="ts" setup>
|
||||
import { useBaseStore, useFormatter, useStakingStore, useTxDialog } from '@/stores';
|
||||
import {
|
||||
useBaseStore,
|
||||
useFormatter,
|
||||
useStakingStore,
|
||||
useTxDialog,
|
||||
} from '@/stores';
|
||||
import { computed } from '@vue/reactivity';
|
||||
import { onMounted, ref, type DebuggerEvent } from 'vue';
|
||||
import { Icon } from '@iconify/vue';
|
||||
@ -7,7 +12,7 @@ import type { Key, Validator } from '@/types';
|
||||
|
||||
const staking = useStakingStore();
|
||||
const format = useFormatter();
|
||||
const dialog = useTxDialog()
|
||||
const dialog = useTxDialog();
|
||||
|
||||
const cache = JSON.parse(localStorage.getItem('avatars') || '{}');
|
||||
const avatars = ref(cache || {});
|
||||
@ -189,7 +194,7 @@ const rank = function (position: number) {
|
||||
|
||||
<div class="bg-base-100 px-4 pt-3 pb-4 rounded shadow">
|
||||
<div class="overflow-x-auto">
|
||||
<table class="table w-full">
|
||||
<table class="table staking-table w-full">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" style="width: 3rem; position: relative">#</th>
|
||||
@ -201,11 +206,15 @@ const rank = function (position: number) {
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="(v, i) in list" :key="v.operator_address">
|
||||
<tr
|
||||
v-for="(v, i) in list"
|
||||
:key="v.operator_address"
|
||||
class="hover:bg-gray-100 dark:hover:bg-[#384059]"
|
||||
>
|
||||
<!-- 👉 rank -->
|
||||
<td>
|
||||
<div
|
||||
class="text-xs truncate relative py-2 px-4 rounded-full w-fit"
|
||||
class="text-xs truncate relative px-2 py-1 rounded-full w-fit"
|
||||
:class="`text-${rank(i)}`"
|
||||
>
|
||||
<span
|
||||
@ -218,18 +227,18 @@ const rank = function (position: number) {
|
||||
<!-- 👉 Validator -->
|
||||
<td>
|
||||
<div
|
||||
class="d-flex align-center overflow-hidden"
|
||||
class="flex items-center overflow-hidden"
|
||||
style="max-width: 400px"
|
||||
>
|
||||
<div
|
||||
class="avatar mr-4 relative w-9 rounded-full overflow-hidden"
|
||||
class="avatar mr-4 relative w-8 h-8 rounded-full overflow-hidden"
|
||||
>
|
||||
<div
|
||||
class="w-9 rounded-full bg-gray-400 absolute opacity-10"
|
||||
class="w-8 h-8 rounded-full bg-gray-400 absolute opacity-10"
|
||||
></div>
|
||||
<div class="w-9 rounded-full">
|
||||
<div class="w-8 h-8 rounded-full">
|
||||
<img
|
||||
v-if="logo(v.description?.identity) !== ''"
|
||||
v-if="v.description?.identity"
|
||||
v-lazy="logo(v.description?.identity)"
|
||||
class="object-contain"
|
||||
/>
|
||||
@ -241,7 +250,7 @@ const rank = function (position: number) {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="d-flex flex-column">
|
||||
<div class="flex flex-col">
|
||||
<h6 class="text-sm text-primary">
|
||||
<RouterLink
|
||||
:to="{
|
||||
@ -262,7 +271,7 @@ const rank = function (position: number) {
|
||||
|
||||
<!-- 👉 Voting Power -->
|
||||
<td class="text-right">
|
||||
<div class="d-flex flex-column">
|
||||
<div class="flex flex-col">
|
||||
<h6 class="text-sm font-weight-medium">
|
||||
{{
|
||||
format.formatToken(
|
||||
@ -309,7 +318,16 @@ const rank = function (position: number) {
|
||||
</td>
|
||||
<!-- 👉 Action -->
|
||||
<td>
|
||||
<label for="delegate" class="btn btn-xs bg-primary" @click="dialog.open('delegate', {validator_address: v.operator_address})">Delegate</label>
|
||||
<label
|
||||
for="delegate"
|
||||
class="btn btn-xs bg-primary"
|
||||
@click="
|
||||
dialog.open('delegate', {
|
||||
validator_address: v.operator_address,
|
||||
})
|
||||
"
|
||||
>Delegate</label
|
||||
>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
@ -345,3 +363,10 @@ const rank = function (position: number) {
|
||||
}
|
||||
}
|
||||
</route>
|
||||
|
||||
<style>
|
||||
.staking-table.table :where(th, td) {
|
||||
padding: 8px 5px;
|
||||
background: transparent;
|
||||
}
|
||||
</style>
|
||||
|
@ -39,9 +39,7 @@ onMounted(() => {
|
||||
<template>
|
||||
<div>
|
||||
<div class="bg-base-100 px-4 pt-3 pb-4 rounded mb-4 shadow">
|
||||
<h2 class="card-title truncate mb-2">
|
||||
What's State Sync?
|
||||
</h2>
|
||||
<h2 class="card-title truncate mb-2">What's State Sync?</h2>
|
||||
<div class="text-sm">
|
||||
The Tendermint Core 0.34 release includes support for state sync, which
|
||||
allows a new node to join a network by fetching a snapshot of the
|
||||
@ -58,14 +56,17 @@ onMounted(() => {
|
||||
</div>
|
||||
|
||||
<div class="bg-base-100 px-4 pt-3 pb-4 rounded mb-4 shadow">
|
||||
<h2 class="card-title truncate mb-2">Starting New Node From State Sync</h2>
|
||||
<h2 class="card-title truncate mb-2">
|
||||
Starting New Node From State Sync
|
||||
</h2>
|
||||
<div class="text-sm">
|
||||
1. Install Binary ({{ appName }} Version:
|
||||
{{ nodeInfo.application_version?.version || '' }})
|
||||
<br />
|
||||
We need to install the binary first and make sure that the version is
|
||||
the one currently in use on mainnet.
|
||||
<br /> <br />
|
||||
<br />
|
||||
<br />
|
||||
2. Enable State Sync<br />
|
||||
We can configure Tendermint to use state sync in
|
||||
$DAEMON_HOME/config/config.toml.
|
||||
@ -86,7 +87,7 @@ onMounted(() => {
|
||||
<div class="text-sm">
|
||||
To make state sync works, we can enable snapshot in
|
||||
$DAEMON_HOME/config/app.toml
|
||||
<br/><br/>
|
||||
<br /><br />
|
||||
<VTextarea
|
||||
auto-grow
|
||||
model-value="[state-sync]
|
||||
|
@ -25,9 +25,13 @@ const messages = computed(() => {
|
||||
</script>
|
||||
<template>
|
||||
<div>
|
||||
<VCard v-if="tx.tx_response" title="Summary">
|
||||
<VCardItem class="pt-0">
|
||||
<VTable>
|
||||
<div
|
||||
v-if="tx.tx_response"
|
||||
class="bg-base-100 px-4 pt-3 pb-4 rounded shadow mb-4"
|
||||
>
|
||||
<h2 class="card-title truncate mb-2">Summary</h2>
|
||||
<div class="overflow-auto-x">
|
||||
<table class="table text-sm">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Tx Hash</td>
|
||||
@ -45,10 +49,21 @@ const messages = computed(() => {
|
||||
<tr>
|
||||
<td>Status</td>
|
||||
<td>
|
||||
<VChip v-if="tx.tx_response.code === 0" color="success"
|
||||
>Success</VChip
|
||||
<VChip color="primary">oioio</VChip>
|
||||
<div
|
||||
class="text-xs truncate relative py-2 px-4 rounded-full w-fit mr-2"
|
||||
:class="`text-${
|
||||
tx.tx_response.code === 0 ? 'success' : 'error'
|
||||
}`"
|
||||
>
|
||||
<span v-else><VChip color="error">Failded</VChip></span>
|
||||
<span
|
||||
class="inset-x-0 inset-y-0 opacity-10 absolute"
|
||||
:class="`bg-${
|
||||
tx.tx_response.code === 0 ? 'success' : 'error'
|
||||
}`"
|
||||
></span>
|
||||
{{ tx.tx_response.code === 0 ? 'Success' : 'Failded' }}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@ -82,23 +97,30 @@ const messages = computed(() => {
|
||||
<td>{{ tx.tx.body.memo }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</VTable>
|
||||
</VCardItem>
|
||||
</VCard>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<VCard :title="`Messages: (${messages.length})`" class="my-5">
|
||||
<VCardItem class="pt-0" style="border-top: 2px dotted gray">
|
||||
<div v-for="(msg, i) in messages">
|
||||
<div><DynamicComponent :value="msg" /></div>
|
||||
</div>
|
||||
<div v-if="messages.length === 0">No messages</div>
|
||||
</VCardItem>
|
||||
</VCard>
|
||||
<div
|
||||
v-if="tx.tx_response"
|
||||
class="bg-base-100 px-4 pt-3 pb-4 rounded shadow mb-4"
|
||||
>
|
||||
<h2 class="card-title truncate mb-2">
|
||||
Messages: ({{ messages.length }})
|
||||
</h2>
|
||||
<div class="divider"></div>
|
||||
<div v-for="(msg, i) in messages">
|
||||
<div><DynamicComponent :value="msg" /></div>
|
||||
</div>
|
||||
<div v-if="messages.length === 0">No messages</div>
|
||||
</div>
|
||||
|
||||
<VCard title="JSON">
|
||||
<VCardItem class="pt-0">
|
||||
<vue-json-pretty :data="tx" :deep="3" />
|
||||
</VCardItem>
|
||||
</VCard>
|
||||
<div
|
||||
v-if="tx.tx_response"
|
||||
class="bg-base-100 px-4 pt-3 pb-4 rounded shadow"
|
||||
>
|
||||
<h2 class="card-title truncate mb-2">JSON</h2>
|
||||
<vue-json-pretty :data="tx" :deep="3" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -1,6 +1,7 @@
|
||||
<script lang="ts" setup>
|
||||
import { ref, onMounted, computed, watchEffect } from 'vue';
|
||||
import { fromHex, toBase64 } from '@cosmjs/encoding';
|
||||
import { Icon } from '@iconify/vue';
|
||||
import {
|
||||
useFormatter,
|
||||
useStakingStore,
|
||||
@ -88,35 +89,23 @@ watchEffect(() => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<VRow>
|
||||
<VCol cols="12" md="4">
|
||||
<VCard class="h-full self-center d-flex p-4">
|
||||
<div class="self-center">
|
||||
Current Height: {{ latest.block?.header?.height }}
|
||||
</div>
|
||||
</VCard>
|
||||
</VCol>
|
||||
<VCol cols="12" md="8" class="">
|
||||
<VTextField
|
||||
v-model="keyword"
|
||||
label="Keywords to filter validators"
|
||||
variant="outlined"
|
||||
>
|
||||
<template v-slot:append>
|
||||
<VBtn
|
||||
><VIcon icon="mdi-star" /><span class="d-none d-md-block"
|
||||
>Favorite</span
|
||||
></VBtn
|
||||
>
|
||||
</template>
|
||||
</VTextField>
|
||||
</VCol>
|
||||
</VRow>
|
||||
<div class="bg-base-100 px-5 pt-5">
|
||||
<div class="flex items-center gap-x-4">
|
||||
<div class="text-main text-lg">Current Height: {{ latest.block?.header?.height }}</div>
|
||||
<input
|
||||
type="text"
|
||||
v-model="keyword"
|
||||
placeholder="Keywords to filter validators"
|
||||
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>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<VRow>
|
||||
<VCol v-for="(v, i) in validators" cols="12" md="3" xl="2" class="py-0">
|
||||
<div class="d-flex justify-between">
|
||||
<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="flex items-center justify-between">
|
||||
<VCheckbox
|
||||
v-model="selected"
|
||||
color="warning"
|
||||
@ -128,26 +117,26 @@ watchEffect(() => {
|
||||
>
|
||||
</template>
|
||||
</VCheckbox>
|
||||
<VChip
|
||||
<div
|
||||
v-if="
|
||||
Number(
|
||||
signingInfo[consensusPubkeyToHexAddress(v.consensus_pubkey)]
|
||||
?.missed_blocks_counter || 0
|
||||
) > 0
|
||||
"
|
||||
size="small"
|
||||
class="mt-1"
|
||||
label
|
||||
color="error"
|
||||
>{{
|
||||
class="badge badge-error badge-sm text-white"
|
||||
>
|
||||
{{
|
||||
signingInfo[consensusPubkeyToHexAddress(v.consensus_pubkey)]
|
||||
?.missed_blocks_counter
|
||||
}}</VChip
|
||||
>
|
||||
<VChip v-else size="small" class="mt-1" label color="success">{{
|
||||
signingInfo[consensusPubkeyToHexAddress(v.consensus_pubkey)]
|
||||
?.missed_blocks_counter
|
||||
}}</VChip>
|
||||
}}
|
||||
</div>
|
||||
<div v-else class="mt-1 badge badge-sm text-white bg-yes">
|
||||
{{
|
||||
signingInfo[consensusPubkeyToHexAddress(v.consensus_pubkey)]
|
||||
?.missed_blocks_counter
|
||||
}}
|
||||
</div>
|
||||
</div>
|
||||
<UptimeBar
|
||||
:blocks="commits"
|
||||
@ -155,8 +144,10 @@ watchEffect(() => {
|
||||
toBase64(fromHex(consensusPubkeyToHexAddress(v.consensus_pubkey)))
|
||||
"
|
||||
/>
|
||||
</VCol>
|
||||
</VRow>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="h-6"></div>
|
||||
</div>
|
||||
</template>
|
||||
<route>
|
||||
|
Loading…
Reference in New Issue
Block a user