forked from cerc-io/cosmos-explorer
add pagination
This commit is contained in:
parent
5b897002a5
commit
0a4d8bad06
42
src/components/PaginationBar.vue
Normal file
42
src/components/PaginationBar.vue
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import TwoFactorAuthDialog from '@/plugins/vuetify/@core/components/TwoFactorAuthDialog.vue';
|
||||||
|
import { PageRequest } from '@/types';
|
||||||
|
import type { PropType } from 'vue';
|
||||||
|
import { computed } from 'vue';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
total: { type: Number },
|
||||||
|
limit: { type: Number },
|
||||||
|
current: { type: Number, default: 1},
|
||||||
|
load: { type: Function, required: true },
|
||||||
|
});
|
||||||
|
const showSize = 3
|
||||||
|
const pages = computed(() => {
|
||||||
|
const pages: {color: string, page: number}[] = []
|
||||||
|
if(props.total && props.limit && props.total > props.limit) {
|
||||||
|
let page = 0
|
||||||
|
while(true) {
|
||||||
|
page += 1
|
||||||
|
if( page * props.limit > props.total ) break
|
||||||
|
if( page > showSize && page < (props.total / props.limit - showSize + 1)) {
|
||||||
|
if(!(page >= props.current - 1 && page <= props.current + 1)){
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pages.push({
|
||||||
|
color: page === props.current? 'btn-primary': '',
|
||||||
|
page: page,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return pages
|
||||||
|
})
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<div class="my-5 text-center">
|
||||||
|
<div v-if="total && limit" class="btn-group">
|
||||||
|
<button v-for="{page, color} in pages" class="btn btn-md" :class="color" @click="load(page)">{{ page }}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
@ -54,7 +54,7 @@ const proposalInfo = ref();
|
|||||||
#{{ item?.proposal_id }}</label
|
#{{ item?.proposal_id }}</label
|
||||||
>
|
>
|
||||||
</td>
|
</td>
|
||||||
<td class="w-[35%]">
|
<td class="w-full">
|
||||||
<div>
|
<div>
|
||||||
<RouterLink
|
<RouterLink
|
||||||
:to="`/${chain.chainName}/gov/${item?.proposal_id}`"
|
:to="`/${chain.chainName}/gov/${item?.proposal_id}`"
|
||||||
@ -69,13 +69,13 @@ const proposalInfo = ref();
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td class="w-[25%]">
|
<td class="w-60">
|
||||||
<ProposalProcess
|
<ProposalProcess
|
||||||
:pool="staking.pool"
|
:pool="staking.pool"
|
||||||
:tally="item.final_tally_result"
|
:tally="item.final_tally_result"
|
||||||
></ProposalProcess>
|
></ProposalProcess>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td class="w-36">
|
||||||
<div class="pl-4">
|
<div class="pl-4">
|
||||||
<div
|
<div
|
||||||
class="flex items-center"
|
class="flex items-center"
|
||||||
@ -228,8 +228,8 @@ const proposalInfo = ref();
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<input type="checkbox" id="proposal-detail-modal" class="modal-toggle" />
|
<input type="checkbox" id="proposal-detail-modal" class="modal-toggle" />
|
||||||
<label for="proposal-detail-modal" class="modal sm:!modal-middle">
|
<label for="proposal-detail-modal" class="modal">
|
||||||
<label class="modal-box relative" for="">
|
<label class="modal-box w-11/12 max-w-5xl" for="">
|
||||||
<label
|
<label
|
||||||
for="proposal-detail-modal"
|
for="proposal-detail-modal"
|
||||||
class="btn btn-sm btn-circle absolute right-2 top-2"
|
class="btn btn-sm btn-circle absolute right-2 top-2"
|
||||||
|
@ -95,7 +95,7 @@ const showDiscord = window.location.host.search("ping.pub") > -1
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-if="item?.badgeContent"
|
v-if="item?.badgeContent"
|
||||||
class="mr-6 badge badge-sm rounded-none" :class="item?.badgeClass"
|
class="mr-6 badge badge-sm" :class="item?.badgeClass"
|
||||||
>
|
>
|
||||||
{{ item?.badgeContent }}
|
{{ item?.badgeContent }}
|
||||||
</div>
|
</div>
|
||||||
|
@ -8,6 +8,7 @@ import {
|
|||||||
type Registry,
|
type Registry,
|
||||||
type AbstractRegistry,
|
type AbstractRegistry,
|
||||||
} from './registry';
|
} from './registry';
|
||||||
|
import { PageRequest } from '@/types';
|
||||||
|
|
||||||
export class BaseRestClient<R extends AbstractRegistry> {
|
export class BaseRestClient<R extends AbstractRegistry> {
|
||||||
endpoint: string;
|
endpoint: string;
|
||||||
@ -98,10 +99,11 @@ export class CosmosRestClient extends BaseRestClient<RequestRegistry> {
|
|||||||
async getGovParamsTally() {
|
async getGovParamsTally() {
|
||||||
return this.request(this.registry.gov_params_tally, {});
|
return this.request(this.registry.gov_params_tally, {});
|
||||||
}
|
}
|
||||||
async getGovProposals(status: string, limit = 20) {
|
async getGovProposals(status: string, page?: PageRequest) {
|
||||||
const query =
|
if(!page) page = new PageRequest()
|
||||||
'?proposal_status={status}&pagination.limit={limit}&pagination.reverse=true&pagination.key=';
|
page.reverse = true
|
||||||
return this.request(this.registry.gov_proposals, { status, limit }, query);
|
const query =`?proposal_status={status}&${page.toQueryString()}`;
|
||||||
|
return this.request(this.registry.gov_proposals, { status }, query);
|
||||||
}
|
}
|
||||||
async getGovProposal(proposal_id: string) {
|
async getGovProposal(proposal_id: string) {
|
||||||
return this.request(this.registry.gov_proposals_proposal_id, {
|
return this.request(this.registry.gov_proposals_proposal_id, {
|
||||||
|
@ -42,7 +42,7 @@ import type {
|
|||||||
Validator,
|
Validator,
|
||||||
} from '@/types/staking';
|
} from '@/types/staking';
|
||||||
import type { PaginatedTxs, Tx, TxResponse } from '@/types/tx';
|
import type { PaginatedTxs, Tx, TxResponse } from '@/types/tx';
|
||||||
|
import semver from 'semver'
|
||||||
export interface Request<T> {
|
export interface Request<T> {
|
||||||
url: string;
|
url: string;
|
||||||
adapter: (source: any) => T;
|
adapter: (source: any) => T;
|
||||||
|
@ -2,8 +2,13 @@
|
|||||||
import { useGovStore } from '@/stores';
|
import { useGovStore } from '@/stores';
|
||||||
import ProposalListItem from '@/components/ProposalListItem.vue';
|
import ProposalListItem from '@/components/ProposalListItem.vue';
|
||||||
import { ref, onMounted } from 'vue';
|
import { ref, onMounted } from 'vue';
|
||||||
|
import PaginationBar from '@/components/PaginationBar.vue';
|
||||||
|
import { PageRequest } from '@/types';
|
||||||
|
|
||||||
const tab = ref('2');
|
const tab = ref('2');
|
||||||
const store = useGovStore();
|
const store = useGovStore();
|
||||||
|
const pageNo = ref({} as Record<string, number>)
|
||||||
|
const pageRequest = ref(new PageRequest())
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
store.fetchProposals('2').then((x) => {
|
store.fetchProposals('2').then((x) => {
|
||||||
@ -11,17 +16,25 @@ onMounted(() => {
|
|||||||
tab.value = '3';
|
tab.value = '3';
|
||||||
store.fetchProposals('3');
|
store.fetchProposals('3');
|
||||||
}
|
}
|
||||||
|
store.fetchProposals('3');
|
||||||
|
store.fetchProposals('4');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
const changeTab = (val: '2' | '3' | '4') => {
|
const changeTab = (val: '2' | '3' | '4') => {
|
||||||
tab.value = val;
|
tab.value = val;
|
||||||
store.fetchProposals(val);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function page(p: number) {
|
||||||
|
pageNo.value[tab.value] = p
|
||||||
|
pageRequest.value.setPage(p)
|
||||||
|
store.fetchProposals(tab.value, pageRequest.value)
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div class="tabs tabs-boxed bg-transparent mb-4">
|
<div class="tabs tabs-boxed bg-transparent mb-4 text-center">
|
||||||
<a
|
<a
|
||||||
class="tab text-gray-400 uppercase"
|
class="tab text-gray-400 uppercase"
|
||||||
:class="{ 'tab-active': tab === '2' }"
|
:class="{ 'tab-active': tab === '2' }"
|
||||||
@ -42,6 +55,7 @@ const changeTab = (val: '2' | '3' | '4') => {
|
|||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
<ProposalListItem :proposals="store?.proposals[tab]"/>
|
<ProposalListItem :proposals="store?.proposals[tab]"/>
|
||||||
|
<PaginationBar :total="store?.proposals[tab]?.pagination?.total" :limit="pageRequest.limit" :current="pageNo[tab]" :load="page"/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<route>
|
<route>
|
||||||
|
@ -32,10 +32,10 @@ export const useGovStore = defineStore('govStore', {
|
|||||||
this.fetchProposals("2");
|
this.fetchProposals("2");
|
||||||
},
|
},
|
||||||
async fetchProposals(status: string, pagination?: PageRequest) {
|
async fetchProposals(status: string, pagination?: PageRequest) {
|
||||||
if (!this.loading[status]) {
|
//if (!this.loading[status]) {
|
||||||
this.loading[status] = LoadingStatus.Loading;
|
this.loading[status] = LoadingStatus.Loading;
|
||||||
const proposals = reactive(
|
const proposals = reactive(
|
||||||
await this.blockchain.rpc?.getGovProposals(status)
|
await this.blockchain.rpc?.getGovProposals(status, pagination)
|
||||||
);
|
);
|
||||||
if (status === '2') {
|
if (status === '2') {
|
||||||
proposals?.proposals?.forEach((item) => {
|
proposals?.proposals?.forEach((item) => {
|
||||||
@ -44,7 +44,7 @@ export const useGovStore = defineStore('govStore', {
|
|||||||
});
|
});
|
||||||
if (this.walletstore.currentAddress) {
|
if (this.walletstore.currentAddress) {
|
||||||
try {
|
try {
|
||||||
this.fetchProposalVotesVoter(item.proposal_id,this.walletstore.currentAddress).then((res) => {
|
this.fetchProposalVotesVoter(item.proposal_id, this.walletstore.currentAddress).then((res) => {
|
||||||
item.voterStatus = res?.vote?.option || 'No With Veto'
|
item.voterStatus = res?.vote?.option || 'No With Veto'
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -58,7 +58,7 @@ export const useGovStore = defineStore('govStore', {
|
|||||||
|
|
||||||
this.loading[status] = LoadingStatus.Loaded;
|
this.loading[status] = LoadingStatus.Loaded;
|
||||||
this.proposals[status] = proposals;
|
this.proposals[status] = proposals;
|
||||||
}
|
//}
|
||||||
return this.proposals[status];
|
return this.proposals[status];
|
||||||
},
|
},
|
||||||
async fetchParams() {
|
async fetchParams() {
|
||||||
|
@ -15,7 +15,28 @@ export interface Pagination {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class PageRequest {
|
export class PageRequest {
|
||||||
limit?: number;
|
key?: string;
|
||||||
|
limit: number;
|
||||||
|
offset?: number;
|
||||||
|
count_total: boolean;
|
||||||
|
reverse?: boolean;
|
||||||
|
constructor() {
|
||||||
|
this.limit = 20
|
||||||
|
this.count_total = true
|
||||||
|
}
|
||||||
|
toQueryString() {
|
||||||
|
const query = []
|
||||||
|
if(this.key) query.push(`pagination.key=${this.key}`)
|
||||||
|
if(this.limit) query.push(`pagination.limit=${this.limit}`)
|
||||||
|
if(this.offset) query.push(`pagination.offset=${this.offset}`)
|
||||||
|
if(this.count_total) query.push(`pagination.count_total=${this.count_total}`)
|
||||||
|
if(this.reverse) query.push(`pagination.reverse=${this.reverse}`)
|
||||||
|
return query.join('&')
|
||||||
|
}
|
||||||
|
setPage(page: number) {
|
||||||
|
if(page >= 1) this.offset = (page - 1) * this.limit
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PaginatedResponse {
|
export interface PaginatedResponse {
|
||||||
|
Loading…
Reference in New Issue
Block a user