iuna

iuna - experimental devnet protocol
git clone https://iuna.jhx.app/git/iuna.git
Log | Files | Refs | README | LICENSE

commit 0fd31183b0337e6637430ced05d89129dcab250f
parent 889ac402ec70a85e3233cbab38e7fbe8ce482bf3
Author: Joris Hartog <jorishartog@hotmail.com>
Date:   Sun,  2 Aug 2026 21:38:59 +0200

Avoid visible loaders during polling

Diffstat:
Msrc/adapters/http.rs | 12++++++++++--
Mwww/assets/iuna-ui.js | 46+++++++++++++++++++++++++++++-----------------
2 files changed, 39 insertions(+), 19 deletions(-)

diff --git a/src/adapters/http.rs b/src/adapters/http.rs @@ -2863,7 +2863,7 @@ const INDEX_HTML: &str = r#"<!doctype html> .block-card { flex-basis: 108px; } } </style> - <script defer src="/assets/iuna-ui.js?v=72"></script> + <script defer src="/assets/iuna-ui.js?v=73"></script> <script defer src="/assets/alpine.min.js"></script> </head> <body x-data="iunaApp()" x-init="init()" @keydown.window.escape="closeModals()" x-cloak> @@ -4742,7 +4742,7 @@ mod tests { #[test] fn metrics_screen_includes_block_range_filter() { - assert!(super::INDEX_HTML.contains("iuna-ui.js?v=72")); + assert!(super::INDEX_HTML.contains("iuna-ui.js?v=73")); assert!(super::INDEX_HTML.contains("aria-label=\"Metrics block range\"")); assert!(super::INDEX_HTML.contains("setMetricsRange(100)")); assert!(super::INDEX_HTML.contains("setMetricsRange(1000)")); @@ -4750,6 +4750,14 @@ mod tests { } #[test] + fn polling_refreshes_paged_datasets_without_visible_loaders() { + let app_js = include_str!("../../www/assets/iuna-ui.js"); + assert!(app_js.contains("setInterval(() => this.refresh({ silent: true }), 5000)")); + assert!(app_js.contains("backgroundLoading")); + assert!(app_js.contains("options.silent === true ? \"backgroundLoading\" : \"loading\"")); + } + + #[test] fn mine_screen_shows_fixed_pow_reward_without_burn_slider() { let app_js = include_str!("../../www/assets/iuna-ui.js"); assert!(app_js.contains("powMineReward()")); diff --git a/www/assets/iuna-ui.js b/www/assets/iuna-ui.js @@ -89,10 +89,10 @@ window.iunaApp = function iunaApp() { newBlockTimer: null, blockPageSize: 20, datasetPageSize: 25, - walletTxPage: { offset: 0, total: 0, hasMore: true, loading: false }, - walletUtxoPage: { offset: 0, total: 0, hasMore: true, loading: false }, - mempoolPage: { offset: 0, total: 0, hasMore: true, loading: false }, - peerPage: { offset: 0, total: 0, hasMore: true, loading: false }, + walletTxPage: { offset: 0, total: 0, hasMore: true, loading: false, backgroundLoading: false }, + walletUtxoPage: { offset: 0, total: 0, hasMore: true, loading: false, backgroundLoading: false }, + mempoolPage: { offset: 0, total: 0, hasMore: true, loading: false, backgroundLoading: false }, + peerPage: { offset: 0, total: 0, hasMore: true, loading: false, backgroundLoading: false }, init() { this.bootstrap(); @@ -119,7 +119,7 @@ window.iunaApp = function iunaApp() { await this.refresh(); this.checkLatestRelease(); if (!this.pollHandle) { - this.pollHandle = setInterval(() => this.refresh(), 5000); + this.pollHandle = setInterval(() => this.refresh({ silent: true }), 5000); } }, @@ -509,7 +509,7 @@ window.iunaApp = function iunaApp() { } }, - async refresh() { + async refresh(options = {}) { try { const [config, status, blocks, p2pMetrics, blockchainMetrics, networkHealth] = await Promise.all([ this.fetchJson("/api/config"), @@ -520,10 +520,10 @@ window.iunaApp = function iunaApp() { this.fetchJson("/api/network/health"), ]); await Promise.all([ - this.refreshPagedDataset("walletTx"), - this.refreshPagedDataset("walletUtxo"), - this.refreshPagedDataset("mempool"), - this.refreshPagedDataset("peer"), + this.refreshPagedDataset("walletTx", { silent: options.silent === true }), + this.refreshPagedDataset("walletUtxo", { silent: options.silent === true }), + this.refreshPagedDataset("mempool", { silent: options.silent === true }), + this.refreshPagedDataset("peer", { silent: options.silent === true }), ]); this.config = config; this.syncConfigState(); @@ -599,25 +599,36 @@ window.iunaApp = function iunaApp() { const config = this.datasetConfig(kind); if (!config) return; this[config.items] = []; - Object.assign(this[config.page], { offset: 0, total: 0, hasMore: true, loading: false }); + Object.assign(this[config.page], { + offset: 0, + total: 0, + hasMore: true, + loading: false, + backgroundLoading: false, + }); await this.refreshPagedDataset(kind); }, - async refreshPagedDataset(kind) { + async refreshPagedDataset(kind, options = {}) { const config = this.datasetConfig(kind); if (!config) return; const page = this[config.page]; - if (page.loading) return; + if (page.loading || page.backgroundLoading) return; const currentLength = this[config.items].length; const limit = Math.max(this.datasetPageSize, currentLength || 0); - await this.loadPagedDataset(kind, { offset: 0, limit, replace: true }); + await this.loadPagedDataset(kind, { + offset: 0, + limit, + replace: true, + silent: options.silent === true, + }); }, async loadNextPage(kind) { const config = this.datasetConfig(kind); if (!config) return; const page = this[config.page]; - if (page.loading || !page.hasMore) return; + if (page.loading || page.backgroundLoading || !page.hasMore) return; await this.loadPagedDataset(kind, { offset: page.offset ?? this[config.items].length, limit: this.datasetPageSize, @@ -628,7 +639,8 @@ window.iunaApp = function iunaApp() { async loadPagedDataset(kind, options) { const config = this.datasetConfig(kind); const page = this[config.page]; - page.loading = true; + const loadingKey = options.silent === true ? "backgroundLoading" : "loading"; + page[loadingKey] = true; try { const payload = await this.fetchJson( this.paginatedPath(config.path(), options.offset, options.limit) @@ -647,7 +659,7 @@ window.iunaApp = function iunaApp() { } catch (error) { this.showFlash(error.message, "error"); } finally { - page.loading = false; + page[loadingKey] = false; } },