From a66bbae4119f4177edf5c56d681ce63409eddf28 Mon Sep 17 00:00:00 2001 From: norwnd Date: Fri, 10 Jan 2025 08:09:14 +0200 Subject: [PATCH] use age instead of time column for recent matches (since time is hard to make sense of when matches aren't happening constantly all the time), but format it slightly differently from how it was --- client/asset/eth/multirpc.go | 4 +- client/webserver/site/src/css/utilities.scss | 4 ++ client/webserver/site/src/html/markets.tmpl | 6 +- client/webserver/site/src/html/wallets.tmpl | 8 --- client/webserver/site/src/js/doc.ts | 71 +++++++++++++------- client/webserver/site/src/js/markets.ts | 16 ++--- client/webserver/site/src/js/wallets.ts | 22 +----- 7 files changed, 65 insertions(+), 66 deletions(-) diff --git a/client/asset/eth/multirpc.go b/client/asset/eth/multirpc.go index 18a633f6a9..38ef3b286f 100644 --- a/client/asset/eth/multirpc.go +++ b/client/asset/eth/multirpc.go @@ -279,7 +279,9 @@ func (p *provider) subscribeHeaders(ctx context.Context, sub ethereum.Subscripti // will never return because geth does not use a timeout. doneUnsubbing := make(chan struct{}) go func() { - sub.Unsubscribe() + if sub != nil { + sub.Unsubscribe() + } close(doneUnsubbing) }() select { diff --git a/client/webserver/site/src/css/utilities.scss b/client/webserver/site/src/css/utilities.scss index d058f7a6e8..ccbfa46f17 100644 --- a/client/webserver/site/src/css/utilities.scss +++ b/client/webserver/site/src/css/utilities.scss @@ -131,6 +131,10 @@ sup.token-parent { white-space: pre-line; } +.preserve-spaces { + white-space:pre; +} + .vscroll { @extend .stylish-overflow; diff --git a/client/webserver/site/src/html/markets.tmpl b/client/webserver/site/src/html/markets.tmpl index a86c48985f..baa3b4aa0c 100644 --- a/client/webserver/site/src/html/markets.tmpl +++ b/client/webserver/site/src/html/markets.tmpl @@ -413,9 +413,9 @@ - + - + @@ -423,7 +423,7 @@ - + diff --git a/client/webserver/site/src/html/wallets.tmpl b/client/webserver/site/src/html/wallets.tmpl index 3e8fc9eb9f..35490b63fa 100644 --- a/client/webserver/site/src/html/wallets.tmpl +++ b/client/webserver/site/src/html/wallets.tmpl @@ -91,14 +91,6 @@
- - - - - - - - diff --git a/client/webserver/site/src/js/doc.ts b/client/webserver/site/src/js/doc.ts index c1dfc1998e..ae87053b1c 100644 --- a/client/webserver/site/src/js/doc.ts +++ b/client/webserver/site/src/js/doc.ts @@ -671,8 +671,8 @@ export default class Doc { * ageSinceFromMs returns a string representation of the duration since the * specified unix timestamp (milliseconds). */ - static ageSinceFromMs (ms: number): string { - return Doc.formatDuration((new Date().getTime()) - ms) + static ageSinceFromMs (ms: number, trimSeconds?: boolean): string { + return Doc.formatDuration((new Date().getTime()) - ms, trimSeconds) } /* @@ -696,9 +696,9 @@ export default class Doc { } /* - * hmsSinceFromS returns a time duration since the specified unix timestamp - * formatted as YYYY/MM/DD hh:mm. - */ + * hmsSinceFromS returns a time duration since the specified unix timestamp + * formatted as YYYY/MM/DD hh:mm. + */ static ymdhmSinceFromMS (ms: number): string { const date = new Date(ms) const year = String(date.getFullYear()) @@ -710,29 +710,54 @@ export default class Doc { } /* formatDuration returns a string representation of the duration */ - static formatDuration (dur: number): string { + static formatDuration (dur: number, trimSeconds?: boolean): string { let seconds = Math.floor(dur) let result = '' - let count = 0 - const add = (n: number, s: string) => { - if (n > 0 || count > 0) count++ - if (n > 0) result += `${n}${s} ` - return count >= 2 + // significantChunkCnt counts how many chunks (year, month, day, hour, minute) we've added to the result. + let significantChunkCnt = 0 + const add = (n: number, s: string): boolean => { + if (n === 0 && significantChunkCnt === 0) { + // we haven't started building the result, so we aren't done yet + return false + } + significantChunkCnt++ + let chunk = `${n}${s} ` + if (n < 10) { + // gotta pad 1-digit number chunk so that it occupies the same amount of space as 2-digit chunk + chunk = ' ' + chunk // use a space that's of the same size as a digit + } + result += chunk + return significantChunkCnt >= 2 // we want to show 2 chunks (year, month, day, hour, minute) at most } - let y, mo, d, h, m, s - [y, seconds] = timeMod(seconds, aYear) - if (add(y, 'y')) { return result } - [mo, seconds] = timeMod(seconds, aMonth) - if (add(mo, 'mo')) { return result } - [d, seconds] = timeMod(seconds, aDay) - if (add(d, 'd')) { return result } + + const aYear = 31536000000 + const aMonth = 2592000000 + const aDay = 86400000 + const anHour = 3600000 + const aMinute = 60000 + const aSecond = 1000 + + let Y, M, D, h, m, s + [Y, seconds] = timeMod(seconds, aYear) + if (add(Y, 'y')) { return result } + [M, seconds] = timeMod(seconds, aMonth) + if (add(M, 'm')) { return result } + [D, seconds] = timeMod(seconds, aDay) + if (add(D, 'd')) { return result } [h, seconds] = timeMod(seconds, anHour) if (add(h, 'h')) { return result } + if (trimSeconds) { + // show minutes chunk and be done with it + [m, seconds] = timeMod(seconds, aMinute) + add(m, 'm') + return result || '0m' + } + // show both minutes and seconds chunks then [m, seconds] = timeMod(seconds, aMinute) if (add(m, 'm')) { return result } - [s, seconds] = timeMod(seconds, 1000) + [s, seconds] = timeMod(seconds, aSecond) add(s, 's') - return result.trimEnd() || '0s' + return result || '0s' } // showFormError can be used to set and display error message on forms. @@ -875,12 +900,6 @@ function sleep (ms: number) { return new Promise(resolve => setTimeout(resolve, ms)) } -const aYear = 31536000000 -const aMonth = 2592000000 -const aDay = 86400000 -const anHour = 3600000 -const aMinute = 60000 - /* timeMod returns the quotient and remainder of t / dur. */ function timeMod (t: number, dur: number) { const n = Math.floor(t / dur) diff --git a/client/webserver/site/src/js/markets.ts b/client/webserver/site/src/js/markets.ts index 636bff407f..2fbdbeaa37 100644 --- a/client/webserver/site/src/js/markets.ts +++ b/client/webserver/site/src/js/markets.ts @@ -202,7 +202,7 @@ export default class MarketsPage extends BasePage { this.recentMatches = [] this.hovers = [] // 'Recent Matches' list sort key and direction. - this.recentMatchesSortKey = 'time' + this.recentMatchesSortKey = 'age' this.recentMatchesSortDirection = -1 // store original title so we can re-append it when updating market value. this.ogTitle = document.title @@ -449,8 +449,8 @@ export default class MarketsPage extends BasePage { for (const mord of Object.values(this.recentlyActiveUserOrders)) { mord.details.age.textContent = Doc.ageSinceFromMs(mord.ord.submitTime) } - for (const td of Doc.applySelector(page.recentMatchesLiveList, '[data-tmpl=time]')) { - td.textContent = Doc.timeFromMs(parseFloat(td.dataset.timestampMs ?? '0')) + for (const td of Doc.applySelector(page.recentMatchesLiveList, '[data-tmpl=age]')) { + td.textContent = Doc.ageSinceFromMs(parseFloat(td.dataset.timestampMs ?? '0'), true) } }, 1000) @@ -572,7 +572,7 @@ export default class MarketsPage extends BasePage { return } - const recentMatches = this.recentMatchesSorted('time', -1) // freshest first + const recentMatches = this.recentMatchesSorted('age', -1) // freshest first if (recentMatches.length === 0) { // not enough info to display current market price setDummyValues() @@ -1280,7 +1280,7 @@ export default class MarketsPage extends BasePage { // update header for "matches" section page.priceHdr.textContent = `Price (${Doc.shortSymbol(this.market.quote.symbol)})` - page.timeHdr.textContent = 'Time' + page.ageHdr.textContent = 'Age' page.qtyHdr.textContent = `Size (${Doc.shortSymbol(this.market.base.symbol)})` } @@ -2661,7 +2661,7 @@ export default class MarketsPage extends BasePage { return this.recentMatches.sort((a: RecentMatch, b: RecentMatch) => direction * (a.rate - b.rate)) case 'qty': return this.recentMatches.sort((a: RecentMatch, b: RecentMatch) => direction * (a.qty - b.qty)) - case 'time': + case 'age': return this.recentMatches.sort((a: RecentMatch, b:RecentMatch) => direction * (a.stamp - b.stamp)) default: return [] @@ -2691,8 +2691,8 @@ export default class MarketsPage extends BasePage { tmpl.price.classList.add(match.sell ? 'sellcolor' : 'buycolor') tmpl.qty.textContent = Doc.formatCoinAtomToLotSizeBaseCurrency(match.qty, mkt.baseUnitInfo, mkt.cfg.lotsize) tmpl.qty.classList.add(match.sell ? 'sellcolor' : 'buycolor') - tmpl.time.textContent = Doc.timeFromMs(match.stamp) - tmpl.time.dataset.timestampMs = String(match.stamp) + tmpl.age.textContent = Doc.ageSinceFromMs(match.stamp, true) + tmpl.age.dataset.timestampMs = String(match.stamp) page.recentMatchesLiveList.append(row) } } diff --git a/client/webserver/site/src/js/wallets.ts b/client/webserver/site/src/js/wallets.ts index 5369a2abc5..02630bc506 100644 --- a/client/webserver/site/src/js/wallets.ts +++ b/client/webserver/site/src/js/wallets.ts @@ -990,7 +990,7 @@ export default class WalletsPage extends BasePage { page.assetLogo.src = Doc.logoPath(symbol) Doc.hide( page.balanceBox, page.fiatBalanceBox, page.createWallet, page.walletDetails, - page.sendReceive, page.connectBttnBox, page.statusLocked, page.statusReady, + page.sendReceive, page.connectBttnBox, page.statusOff, page.connectBttnBox, page.peerCountBox, page.syncProgressBox, page.statusDisabled, page.tokenInfoBox, page.needsProviderBox, page.feeStateBox, page.txSyncBox, page.txProgress, page.txFindingAddrs @@ -1021,14 +1021,11 @@ export default class WalletsPage extends BasePage { updateSyncAndPeers (assetID: number) { const { page, selectedAssetID } = this if (assetID !== selectedAssetID) return - const { peerCount, syncProgress, syncStatus, open, running } = app().walletMap[assetID] + const { peerCount, syncProgress, syncStatus, running } = app().walletMap[assetID] if (!running) return Doc.show(page.sendReceive, page.peerCountBox, page.syncProgressBox) page.peerCount.textContent = String(peerCount) page.syncProgress.textContent = `${(syncProgress * 100).toFixed(1)}%` - if (open) { - Doc.show(page.statusReady) - } else Doc.show(page.statusLocked) // wallet not unlocked Doc.setVis(syncStatus.txs !== undefined, page.txSyncBox) if (syncStatus.txs !== undefined) { Doc.hide(page.txProgress, page.txFindingAddrs) @@ -2007,21 +2004,6 @@ export default class WalletsPage extends BasePage { this.showForm(this.page.recoverWalletConfirm) } - /* Show the open wallet form if the password is not cached, and otherwise - * attempt to open the wallet. - */ - async openWallet (assetID: number) { - const open = { - assetID: assetID - } - const res = await postJSON('/api/openwallet', open) - if (!app().checkResponse(res)) { - console.error('openwallet error', res) - return - } - this.assetUpdated(assetID, undefined, intl.prep(intl.ID_WALLET_UNLOCKED)) - } - /* Show the form used to change wallet configuration settings. */ async showReconfig (assetID: number, cfg?: reconfigSettings) { const page = this.page
[[[Status]]][[[:title:locked]]]
[[[Status]]][[[:title:ready]]]
[[[Status]]] [[[:title:off]]]