Skip to content

Commit

Permalink
Merge pull request #183 from rsksmart/fix/request-specific-data
Browse files Browse the repository at this point in the history
Optimize tabs data fetching
  • Loading branch information
ezequiel-rodriguez authored Dec 15, 2023
2 parents d012214 + 6e86cd7 commit d8c7519
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 81 deletions.
1 change: 1 addition & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

175 changes: 97 additions & 78 deletions src/components/DataPage.vue
Original file line number Diff line number Diff line change
@@ -1,57 +1,70 @@
<template lang="pug">
.data-page.centered
h2.title(v-if='pageTitle') {{pageTitle}}
spinner(v-if='(requesting && !error && !delayed.fields) || delayed.registry')
error-page(v-if='error' :error='error')
.update-error(v-if='updateError')
h3
span Update Error:&nbsp;
small {{updateError.error}}
template(v-if='!error')
.messages(v-if='pageMessages')
message(v-for='msg,key in pageMessages' :message='msg' :key='key' :data='data')
//- Header
.page-header(v-if='mainContent')
item-navigator(v-if='!isTable' :next='next' :prev='prev' :total='total' :regKey='dataKey()(dataType)')

.tabs
.tabs-titles(v-if='page.data')
template(v-for='tab in mainContentTabs')
button.btn.tab-title(v-if='tab.name' @click='setActiveContentTab(tab.name,$event)'
:class='tabTitleCss(isActiveContentTab(tab))')
span.title {{ tab.name }} {{ (undefined !== tab.total) ? `(${tab.total})` : '' }}
icon(v-if='tab.buttonIcon' :name='tab.buttonIcon')
export-controls(v-if='data' :data='page.data' :type='dataType')
data-section( v-if='activeContentTab'
:component='activeContentTab.component' :reqKey='reqKey' :module='module'
:dataType='activeContentTab.dataType || dataType' :action='action' :updateOnNewBlock='updateOnNewBlock' @update='updateSection')
.page(v-if='data')
data-section(v-if='!tabs && !activeContentTab' :module='module' :dataType='dataType'
:reqKey='reqKey' :component='component' :action='action' :updateOnNewBlock='updateOnNewBlock' @update='updateSection')
.tabs(v-if='tabs && data && !hideTabs')
//- Tabs titles
.tabs-titles(v-if='page.data')
template(v-for='tab in tabs')
template(v-if='renderTab(tab)')
template(v-if='isRequesting()(tab.name)')
button.btn.tab-title
loading-circle(:size='10')
span.title {{ getTabTitle(tab) }}
template(v-else)
button.btn.tab-title(@click='setTab(tab.name,$event)' :class='tabTitleCss(isActiveTab(tab))')
span.title {{ getTabTitle(tab) }}
small.small(v-if='tabsTotals[tab.name] !== null') &nbsp; ({{ tabsTotals[tab.name] }})

template(v-for='tab in tabs')
template(v-if='isActiveTab(tab)')
spinner(v-if='isRequesting()(tab.name)')
data-section.tab-content(v-else :module='tab.module' :dataType='tab.dataType'
:reqKey='tab.name' :action='tab.action' :msgs='tab.msgs')

<template>
<div class="data-page centered">
<h2 class="title" v-if="titleDescription">{{ titleDescription }}</h2>
<spinner v-if="(requesting && !error && !delayed.fields) || delayed.registry"></spinner>
<error-page v-if="error" :error="error"></error-page>
<div class="update-error" v-if="updateError">
<h3>
<span>Update Error:&nbsp;</span>
<small>{{ updateError.error }}</small>
</h3>
</div>
<template v-if="!error">
<div class="messages" v-if="pageMessages">
<message v-for="(msg, key) in pageMessages" :message="msg" :key="key" :data="data"></message>
</div>
<!-- Header -->
<div class="page-header" v-if="mainContent">
<item-navigator v-if="!isTable" :next="next" :prev="prev" :total="total" :regKey="dataKey()(dataType)"></item-navigator>
<div class="tabs">
<div class="tabs-titles" v-if="page.data">
<template v-for="tab in mainContentTabs">
<button class="btn tab-title" :key="tab.name" v-if="tab.name" @click="setActiveContentTab(tab.name, $event)" :class="tabTitleCss(isActiveContentTab(tab))">
<span class="title">{{ tab.name }} {{ (undefined !== tab.total) ? `(${tab.total})` : '' }}</span>
<icon v-if="tab.buttonIcon" :name="tab.buttonIcon"></icon>
</button>
</template>
<export-controls v-if="data" :data="page.data" :type="dataType"></export-controls>
</div>
<data-section v-if="activeContentTab" :component="activeContentTab.component" :reqKey="reqKey" :module="module" :dataType="activeContentTab.dataType || dataType" :action="action" :updateOnNewBlock="updateOnNewBlock" @update="updateSection"></data-section>
</div>
</div>
<div class="page" v-if="data">
<data-section v-if="!tabs && !activeContentTab" :module="module" :dataType="dataType" :reqKey="reqKey" :component="component" :action="action" :updateOnNewBlock="updateOnNewBlock" @update="updateSection"></data-section>
<div class="tabs" v-if="tabs && data && !hideTabs">
<!-- Tabs titles -->
<div class="tabs-titles" v-if="page.data">
<template v-for="(tab, i) in tabs">
<template v-if="renderTab(tab)">
<template v-if="isRequesting()(tab.name)">
<button :key="tab.dataType" class="btn tab-title">
<loading-circle :size="10"></loading-circle>
<span class="title">{{ getTabTitle(tab) }}</span>
</button>
</template>
<template v-else>
<button :key="`${tab.name}-${i}`" class="btn tab-title" @click="setTab(tab.name, $event)" :class="tabTitleCss(isActiveTab(tab))">
<span class="title">{{ getTabTitle(tab) }}
<small class="small" v-if="tabsTotals[tab.name] !== null">&nbsp; ({{ tabsTotals[tab.name] }})</small>
</span>
</button>
</template>
</template>
</template>
</div>
<template v-for="(tab, i) in tabs">
<template v-if="isActiveTab(tab)">
<spinner :key="tab.action" v-if="isRequesting()(tab.name)"></spinner>
<data-section :key="`${tab.module}-${i}`" class="tab-content" v-else :module="tab.module" :dataType="tab.dataType" :reqKey="tab.name" :action="tab.action" :msgs="tab.msgs"></data-section>
</template>
</template>
</div>
</div>
</template>
</div>
</template>
<script>
import { mapActions, mapGetters } from 'vuex'
import { plainObjectChanges } from '../lib/js/utils'
import Spinner from './Spinner.vue'
import LoadingCircle from './LoadingCircle.vue'
import DataSection from './DataSection'
Expand Down Expand Up @@ -92,14 +105,28 @@ export default {
this.getData()
},
watch: {
$route: 'onRouteChange'
$route: 'onRouteChange',
pageTitle (newTitle, oldTitle) {
if (newTitle && typeof newTitle === 'string' && newTitle !== oldTitle) {
this.storedTitle = newTitle
}
}
},
data () {
return {
storedTitle: '',
storedParamAddress: null
}
},
computed: {
...mapGetters({
getActiveTab: 'getActiveTab',
getActiveContentTab: 'getActiveContentTab',
routeParams: 'getRouterParams'
}),
titleDescription () {
return this.pageTitle || this.storedTitle
},
hideTabs () {
const active = this.activeContentTab || {}
return active.hideTabs
Expand Down Expand Up @@ -234,43 +261,35 @@ export default {
if (typeof render === 'function') return render(data, tabsTotals[name])
return (undefined === render) ? true : render
},
onRouteChange (to, from) {
if (to.path === from.path) {
// check for query changes
const diff = plainObjectChanges(to.query, from.query)
const keys = Object.keys(diff)
// dont fetch
if (!keys.length) return
if (keys.length === 1 && keys[0].slice(0, 2) === '__') return
}
onRouteChange () {
this.getData()
},
async getData () {
let { module, tabs, action, params } = this
await this.getParentData()
if (this.tabs) {
await this.fetchTab()
}
},
async getParentData () {
const { module, action, params } = this
const key = this.reqKey
if (!module || !action) return
await this.fetchRouteData({ action, params, module, key })
if (tabs) {
const active = this.activeTab
if (active) {
await this.fetchTab(active)
tabs = tabs.filter(tab => tab.name !== active)
}
for (const tab of tabs) {
this.fetchTab(tab.name)
}
const paramsAddress = this.$route.params?.address
// If the parameters are the same when the router changes, we do not request the address information.
if (this.storedParamAddress !== paramsAddress) {
// use Date for a random info
this.storedParamAddress = paramsAddress || new Date()
return this.fetchRouteData({ action, params, module, key })
}
},
async fetchTab (tabName) {
const tab = Object.assign({}, this.getTab(tabName))
async fetchTab () {
const tab = Object.assign({}, this.getTab(this.activeTab))
let params = tab.params
params = (params && typeof params === 'function') ? params(this.routeParams) : params
params = params || {}
params.count = true // WIP get totals in first request only
params.count = false
tab.params = params
tab.count = true
tab.count = false
if (tab) {
const req = await this.fetchRouteData(tab)
return req
Expand Down
2 changes: 1 addition & 1 deletion src/components/DataSection.vue
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ export default {
return this.getPage()(this.reqKey)
},
delayed () {
return this.page.delayed
return this.page?.delayed
},
data () {
return (this.page) ? this.page.data : null
Expand Down
3 changes: 1 addition & 2 deletions src/store/modules/backend/getters.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,7 @@ export const lastBlocksTime = state => {

export const getPageTotal = (state, getters) => key => {
const data = state.responses[key]
const { pages } = data
const total = (pages && pages.total) ? pages.total : state.totals[key] || null
const total = (data?.pages && data?.pages.total) ? data?.pages.total : state.totals[key] || null
return total
}

Expand Down

0 comments on commit d8c7519

Please sign in to comment.