@@ -15,7 +15,10 @@ import { selectCaseFeed } from '@/lib/caseFeed';
1515import { urlForWatchlist } from '@/lib/navigation' ;
1616import { summarizeNetwork } from '../../shared/protocol/index.ts' ;
1717import { useSlashingStore } from '@/store/slashingStore' ;
18- import type { MonitorConfigInput } from '@/types/slashing' ;
18+ import type {
19+ ExecutionHistoryScan ,
20+ MonitorConfigInput ,
21+ } from '@/types/slashing' ;
1922import type { ProtocolSnapshot } from '../../shared/protocol/index.ts' ;
2023
2124interface DashboardProps {
@@ -58,7 +61,9 @@ export function Dashboard({
5861 config : store . config ,
5962 state : store ,
6063 slashings : [ ...store . detectedSlashings . values ( ) ] ,
64+ confirmedExecutions : store . confirmedExecutions ,
6165 confirmedSlashes : store . confirmedSlashes ,
66+ executionScan : store . executionScan ,
6267 } ) ;
6368 } ) ( ) ;
6469
@@ -200,7 +205,9 @@ export function Dashboard({
200205 />
201206 ) }
202207
203- { store . isScanning && (
208+ { store . executionScan . status !== 'idle' ? (
209+ < ExecutionHistoryStatus scan = { store . executionScan } />
210+ ) : store . isScanning && (
204211 < div className = "mb-8 border-5 border-aqua bg-lapis p-5 shadow-brutal-aqua" >
205212 < p className = "font-black uppercase text-aqua" >
206213 Scanning live and historical slashing rounds…
@@ -239,16 +246,6 @@ export function Dashboard({
239246 ) ) }
240247 </ div >
241248
242- { addresses . length === 0 && (
243- < section className = "mb-8 border-5 border-orchid bg-aubergine p-6 shadow-brutal-orchid" >
244- < h2 className = "text-2xl font-black text-orchid" > Add an address above</ h2 >
245- < p className = "mt-2 text-sm font-bold text-whisper-white/75" >
246- The network overview is public. Address cards make the protocol
247- path actionable for your own sequencers.
248- </ p >
249- </ section >
250- ) }
251-
252249 { projected && (
253250 < CaseFeed
254251 cases = { projected . cases }
@@ -261,3 +258,61 @@ export function Dashboard({
261258 </ main >
262259 ) ;
263260}
261+
262+ function ExecutionHistoryStatus ( { scan } : { scan : ExecutionHistoryScan } ) {
263+ const percentage = scan . totalBlocks === 0n
264+ ? 100
265+ : Math . min (
266+ 100 ,
267+ Number ( scan . scannedBlocks * 10_000n / scan . totalBlocks ) / 100 ,
268+ ) ;
269+ const complete = scan . status === 'complete' ;
270+ const paused = scan . status === 'paused' ;
271+ return (
272+ < section className = { `mb-8 border-5 p-4 ${
273+ complete
274+ ? 'border-chartreuse bg-malachite shadow-brutal-chartreuse'
275+ : paused
276+ ? 'border-orchid bg-aubergine shadow-brutal-orchid'
277+ : 'border-aqua bg-lapis shadow-brutal-aqua'
278+ } `} >
279+ < div className = "flex flex-wrap items-center justify-between gap-2" >
280+ < h2 className = { `text-lg font-black ${
281+ complete
282+ ? 'text-chartreuse'
283+ : paused ? 'text-orchid' : 'text-aqua'
284+ } `} >
285+ { complete
286+ ? 'Execution history complete'
287+ : paused
288+ ? 'Execution history paused'
289+ : 'Scanning execution history' }
290+ </ h2 >
291+ < span className = "font-mono text-xs font-black text-whisper-white/65" >
292+ { scan . scannedBlocks . toString ( ) } / { scan . totalBlocks . toString ( ) } blocks
293+ </ span >
294+ </ div >
295+ < div
296+ role = "progressbar"
297+ aria-label = "Execution history scan coverage"
298+ aria-valuemin = { 0 }
299+ aria-valuemax = { 100 }
300+ aria-valuenow = { percentage }
301+ className = "mt-3 h-4 border-3 border-whisper-white/40 bg-brand-black"
302+ >
303+ < div
304+ className = { `h-full ${
305+ complete
306+ ? 'bg-chartreuse'
307+ : paused ? 'bg-orchid' : 'bg-aqua'
308+ } `}
309+ style = { { width : `${ percentage } %` } }
310+ />
311+ </ div >
312+ < p className = "mt-2 text-xs font-bold text-whisper-white/65" >
313+ RPC chunk { scan . chunkSize . toString ( ) } blocks
314+ { paused ? ' · The next refresh will retry, or you can use another RPC.' : '' }
315+ </ p >
316+ </ section >
317+ ) ;
318+ }
0 commit comments