front: validator_prefs + era_exposure sections on Polkadot detail page#26
Conversation
PolkadotChainSections now renders three Sections when chain_data
is populated:
1. Active Set (existing): currently_elected + observed_at_block
2. Validator Preferences (new): commission % + accepting-nominations
(red 'No (blocked)' when validator_prefs.blocked is true)
3. Era Exposure (new): era_index, total_planck, own_planck,
nominator_count with planckToDot conversion via BigInt to
avoid Number's 53-bit precision ceiling
Each section gated on the corresponding chain_data field being
non-null — graceful degradation when the worker hasn't populated
yet (deploy gap) or when the storage row doesn't exist.
There was a problem hiding this comment.
Code Review
This pull request expands the Polkadot chain data display by adding sections for validator preferences (commission and status) and era exposure (stake and nominator counts). It also introduces a planckToDot utility to safely format large token values using BigInt. Feedback was provided regarding the planckToDot function, noting that hardcoding a decimal point while using localized thousands separators can lead to ambiguous formatting in certain locales.
| const frac = planck % denom; | ||
| // Show 4 fractional digits — beyond that the value is noise for UI. | ||
| const fracStr = (frac / 1_000_000n).toString().padStart(4, '0'); | ||
| return `${whole.toLocaleString()}.${fracStr}`; |
There was a problem hiding this comment.
The planckToDot function currently mixes whole.toLocaleString() (which uses locale-specific thousands separators) with a hardcoded . decimal separator. In locales where the thousands separator is a dot (e.g., German), this produces ambiguous output like 1.234.5678.
To maintain consistency with the localized integer formatting used elsewhere in the file (via formatNumber), you should dynamically determine the decimal separator or use a fixed locale for both parts to ensure the output is clear and correctly formatted.
const sep = new Intl.NumberFormat().formatToParts(1.1).find(p => p.type === 'decimal')?.value ?? '.';
return `${whole.toLocaleString()}${sep}${fracStr}`;
Summary
`PolkadotChainSections` now renders three Sections when chain_data is populated:
Helpers:
Pairs with worker PR slasher-worker#34.
Test plan