Skip to content

Commit

Permalink
Migrate Chain and Chunks Info Page #8350 (#8903)
Browse files Browse the repository at this point in the history
* Migrate Chain and Chunks Info Page #8350

<h1> Problem </h1>
Need migrate chain and chunks info page to Typescript + React framework.

<h1> What has changed </h1>
- Fixed bug on old page for not displaying floating chunks
- Migrated the page with exactly the same format
- used multiple navigation bars

<h1> Testing </h1>
- Ran linter
- Attached before and after screenshots of UI on github issue and pull request
- Manually viewed pages on UI

```
cd nearcore
make debug
nearup run localnet --binary-path ~/Github/near/nearcore/target/debug/
open http://localhost:3030/debug/pages/chain_n_chunk_info

cd nearcore/tools/debug-ui
npm install
npm start
open http://localhost:3000/localhost:3030/chain_and_chunk_info
open http://localhost:3000/localhost:3030/chain_and_chunk_info/chain_info_summary
open http://localhost:3000/localhost:3030/chain_and_chunk_info/floating_chunks
open http://localhost:3000/localhost:3030/chain_and_chunk_info/blocks
```

* Addressed review 1 comments
- Fixed enum format and printing of enum
- Used and instead of conditional operator with a useless else statement
- Added return type to some functions
- Initialize numShards as constant
- Used templated literals
- String concat or string interpolation
  • Loading branch information
SoonNear authored Apr 14, 2023
1 parent 6978079 commit b3df317
Show file tree
Hide file tree
Showing 13 changed files with 536 additions and 5 deletions.
1 change: 1 addition & 0 deletions chain/jsonrpc/res/chain_n_chunk_info.html
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@
row.append($('<td>').append(chunk.chunk_hash));
row.append($('<td>').append(chunk.created_by));
row.append($('<td>').append(chunk.status));
$('.js-floating-chunks-tbody').append(row);
})
generateBlocksTableHeader(num_shards);
}
Expand Down
2 changes: 1 addition & 1 deletion tools/debug-ui/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ more precisely, using TestLoop from core/async/src/test_loop.rs), the test can b
```
cargo test -p near-chunks test_multi -- --show-output > ~/log.txt
```
2. Go to the UI at `/logviz`, such as http://localhost:3030/logviz
2. Go to the UI at `/logviz`, such as http://localhost:3000/logviz
3. Drag the log.txt file into the UI.

Screenshots:
Expand Down
7 changes: 5 additions & 2 deletions tools/debug-ui/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import './App.scss';
import { NavLink } from 'react-router-dom';
import { Navigate, Route, Routes, useParams } from 'react-router';
import { ChainAndChunkInfoView } from './ChainAndChunkInfoView';
import { ClusterView } from './ClusterView';
import { EpochInfoView } from './EpochInfoView';
import { HeaderBar } from './HeaderBar';
Expand All @@ -15,7 +16,6 @@ function useNodeAddr(): string {

export const App = () => {
const addr = useNodeAddr();

return (
<div className="App">
<HeaderBar addr={addr} />
Expand Down Expand Up @@ -47,7 +47,10 @@ export const App = () => {
<Route path="last_blocks" element={<LatestBlocksView addr={addr} />} />
<Route path="network_info/*" element={<NetworkInfoView addr={addr} />} />
<Route path="epoch_info/*" element={<EpochInfoView addr={addr} />} />
<Route path="chain_and_chunk_info" element={<div>TODO</div>} />
<Route
path="chain_and_chunk_info/*"
element={<ChainAndChunkInfoView addr={addr} />}
/>
<Route path="sync_info" element={<div>TODO</div>} />
<Route path="validator_info" element={<div>TODO</div>} />
<Route path="cluster" element={<ClusterView initialAddr={addr} />} />
Expand Down
34 changes: 34 additions & 0 deletions tools/debug-ui/src/BlocksView.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
.chain-and-chunk-blocks-view {
.error {
color: red;
}
}
.chain-and-chunk-blocks-table {
table {
width: 100%;
border-collapse: collapse;
}

table,
th,
td {
border: 1px solid black;
}

td {
text-align: left;
vertical-align: top;
padding: 8px;
}

th {
text-align: center;
vertical-align: center;
padding: 8px;
background-color: lightgrey;
}

tr.active {
background-color: #eff8bf;
}
}
164 changes: 164 additions & 0 deletions tools/debug-ui/src/BlocksView.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
import './BlocksView.scss';
import { useQuery } from 'react-query';
import { fetchChainProcessingStatus, BlockProcessingStatus, ChunkProcessingStatus } from './api';

type BlocksViewProps = {
addr: string;
};

function prettyTime(datetime: string): string {
const time = new Date(Date.parse(datetime));
return String(time.getUTCHours()).concat(
':',
String(time.getUTCMinutes()).padStart(2, '0'),
':',
String(time.getUTCSeconds()).padStart(2, '0'),
'.',
String(time.getUTCMilliseconds()).padStart(3, '0')
);
}

function printTimeInMs(time: number | null): string {
if (time == null) {
return 'N/A';
} else {
return time + 'ms';
}
}

function printDuration(start: string, end: string): string {
const duration = Date.parse(end) - Date.parse(start);
if (duration > 0) {
return `+${duration}ms`;
} else {
return `${duration}ms`;
}
}

function getChunkStatusSymbol(chunkStatus: ChunkProcessingStatus): string {
switch (chunkStatus) {
case 'Completed':
return '✔';
case 'Requested':
return '⬇';
case 'NeedToRequest':
return '.';
default:
return '';
}
}

function printBlockStatus(blockStatus: BlockProcessingStatus): string {
if (typeof blockStatus === 'string') {
return blockStatus;
}
if ('Error' in blockStatus) {
return `Error: ${blockStatus.Error}`;
}
return `Dropped: ${blockStatus.Dropped}`;
}

export const BlocksView = ({ addr }: BlocksViewProps) => {
const {
data: chainProcessingInfo,
error: chainProcessingInfoError,
isLoading: chainProcessingInfoLoading,
} = useQuery(['chainProcessingInfo', addr], () => fetchChainProcessingStatus(addr));
if (chainProcessingInfoLoading) {
return <div>Loading...</div>;
} else if (chainProcessingInfoError) {
return (
<div className="chain-and-chunk-blocks-view">
<div className="error">{(chainProcessingInfoError as Error).stack}</div>
</div>
);
} else if (!chainProcessingInfo) {
return (
<div className="chain-and-chunk-blocks-view">
<div className="error">No Data</div>
</div>
);
}
const numShards =
chainProcessingInfo!.status_response.ChainProcessingStatus.blocks_info[0].chunks_info!
.length;
const shardIndices = [...Array(numShards).keys()];
return (
<div className="chain-and-chunk-blocks-view">
<table className="chain-and-chunk-blocks-table">
<thead>
<tr>
<th>Height</th>
<th>Hash</th>
<th>Received</th>
<th>Status</th>
<th>In Progress for</th>
<th>In Orphan for</th>
<th>Missing Chunks for</th>
{shardIndices.map((shardIndex) => {
return <th key={shardIndex}> Shard {shardIndex} </th>;
})}
</tr>
</thead>
<tbody>
{chainProcessingInfo!.status_response.ChainProcessingStatus.blocks_info.map(
(block) => {
return (
<tr key={block.height}>
<td>{block.height}</td>
<td>{block.hash}</td>
<td>{prettyTime(block.received_timestamp)}</td>
<td>{printBlockStatus(block.block_status)}</td>
<td>{printTimeInMs(block.in_progress_ms)}</td>
<td>{printTimeInMs(block.orphaned_ms)}</td>
<td>{printTimeInMs(block.missing_chunks_ms)}</td>
{block.chunks_info!.map((chunk) => {
if (chunk) {
return (
<td key={chunk.shard_id}>
<strong>{`${
chunk.status
} ${getChunkStatusSymbol(
chunk.status
)}`}</strong>
{chunk.completed_timestamp && (
<>
<br /> Completed @ BR
{`${printDuration(
block.received_timestamp,
chunk.completed_timestamp
)}`}
</>
)}
{chunk.requested_timestamp && (
<>
<br /> Requested @ BR
{`${printDuration(
block.received_timestamp,
chunk.requested_timestamp
)}`}
</>
)}
{chunk.request_duration && (
<>
<br /> Duration
{`${printTimeInMs(
chunk.request_duration
)}`}
</>
)}
</td>
);
} else {
return <td key={block.height}> No Chunk </td>;
}
})}
</tr>
);
}
)}
</tbody>
</table>
</div>
);
};
33 changes: 33 additions & 0 deletions tools/debug-ui/src/ChainAndChunkInfoView.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
.chain-and-chunk-info-view {
.error {
color: red;
}

table {
width: 100%;
border-collapse: collapse;
}

table,
th,
td {
border: 1px solid black;
}

td {
text-align: left;
vertical-align: top;
padding: 8px;
}

th {
text-align: center;
vertical-align: center;
padding: 8px;
background-color: lightgrey;
}

tr.active {
background-color: #eff8bf;
}
}
37 changes: 37 additions & 0 deletions tools/debug-ui/src/ChainAndChunkInfoView.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import './ChainAndChunkInfoView.scss';
import { NavLink, Navigate, Route, Routes } from 'react-router-dom';
import { BlocksView } from './BlocksView';
import { ChainInfoSummaryView } from './ChainInfoSummaryView';
import { FloatingChunksView } from './FloatingChunksView';

type ChainAndChunkInfoViewProps = {
addr: string;
};

export const ChainAndChunkInfoView = ({ addr }: ChainAndChunkInfoViewProps) => {
return (
<div className="chain-and-chunk-info-view">
<div className="navbar">
<NavLink to="chain_info_summary" className={navLinkClassName}>
Chain Info Summary
</NavLink>
<NavLink to="floating_chunks" className={navLinkClassName}>
Floating Chunks
</NavLink>
<NavLink to="blocks" className={navLinkClassName}>
Blocks
</NavLink>
</div>
<Routes>
<Route path="" element={<Navigate to="chain_info_summary" />} />
<Route path="chain_info_summary" element={<ChainInfoSummaryView addr={addr} />} />
<Route path="floating_chunks" element={<FloatingChunksView addr={addr} />} />
<Route path="blocks" element={<BlocksView addr={addr} />} />
</Routes>
</div>
);
};

function navLinkClassName({ isActive }: { isActive: boolean }) {
return isActive ? 'nav-link active' : 'nav-link';
}
5 changes: 5 additions & 0 deletions tools/debug-ui/src/ChainInfoSummaryView.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.chain-info-summary-view {
.error {
color: red;
}
}
Loading

0 comments on commit b3df317

Please sign in to comment.