Skip to content

Commit fdc65b5

Browse files
committed
Fix a bunch of bugs
1 parent 2041a25 commit fdc65b5

File tree

13 files changed

+438
-180
lines changed

13 files changed

+438
-180
lines changed

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ COPY frontend-react/ ./
77
RUN npm run build
88

99
# Build the manager binary
10-
FROM golang:1.24.5 AS builder
10+
FROM golang:1.25.1 AS builder
1111
ARG TARGETOS
1212
ARG TARGETARCH
1313

config.yaml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,6 @@ database:
2424
networks:
2525
- "mainnet"
2626
- "testnet"
27-
- "regtest"
28-
- "stn"
2927
- "teratestnet"
3028
- "tstn"
3129

frontend-react/src/components/Dashboard.tsx

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,8 @@ export const Dashboard: React.FC = () => {
5555

5656
// Check if message matches current filters
5757
const messageNetwork = message.Topic.split('/')[3]?.split('-')[0];
58-
console.log(messageNetwork)
5958
const messageType = message.Topic.split('-')[1];
60-
console.log(messageType)
61-
62-
59+
6360
const matchesNetwork = selectedNetwork === 'all' || messageNetwork === selectedNetwork;
6461
const matchesType = selectedMessageType === 'all' || messageType === selectedMessageType;
6562

@@ -178,13 +175,8 @@ export const Dashboard: React.FC = () => {
178175
switch (messageType) {
179176
case 'block':
180177
return <BlockCard key={item.ID || index} block={item as Block} isNew={isNew} />;
181-
// Temporarily disabling miningon message type
182-
// case 'miningon':
183-
// return <MiningCard key={item.ID || index} mining={item as MiningOn} isNew={isNew} />;
184178
case 'subtree':
185179
return <SubtreeCard key={item.ID || index} subtree={item as Subtree} isNew={isNew} />;
186-
case 'handshake':
187-
return <HandshakeCard key={item.ID || index} handshake={item as Handshake} isNew={isNew} />;
188180
case 'rejected_tx':
189181
return <RejectedTxCard key={item.ID || index} rejectedTx={item as RejectedTx} isNew={isNew} />;
190182
case 'node_status':

frontend-react/src/components/MessageTypeFilter.tsx

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,6 @@ const typeInfo: Record<MessageType | 'all', { label: string; icon: string; descr
2929
icon: '🌳',
3030
description: 'Transaction batch announcements'
3131
},
32-
handshake: {
33-
label: 'Handshakes',
34-
icon: '🤝',
35-
description: 'Peer connection handshakes'
36-
},
3732
rejected_tx: {
3833
label: 'Rejected TX',
3934
icon: '❌',

frontend-react/src/components/Networks.tsx

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import React, { useState, useEffect, useCallback, useMemo } from 'react';
2+
import { useSearchParams } from 'react-router-dom';
23
import { Network, NodeStatus, Message } from '../types/Message';
34
import { ApiService } from '../services/api';
45
import { nodeStatusStore, NodeStatusWithScore } from '../services/nodeStatusStore';
@@ -7,8 +8,27 @@ import { useWebSocket } from '../hooks/useWebSocket';
78
import { PeerNameEditor } from './PeerNameEditor';
89
import { PeerNamesService } from '../services/peerNames';
910

11+
const NETWORK_STORAGE_KEY = 'teranode-selected-network';
12+
1013
const Networks: React.FC = () => {
11-
const [selectedNetwork, setSelectedNetwork] = useState<Network>('mainnet');
14+
const [searchParams, setSearchParams] = useSearchParams();
15+
16+
// Get network from URL query param, then localStorage, then default to mainnet
17+
const getInitialNetwork = (): Network => {
18+
const urlNetwork = searchParams.get('network');
19+
if (urlNetwork && ['mainnet', 'testnet', 'teratestnet', 'tstn'].includes(urlNetwork)) {
20+
return urlNetwork as Network;
21+
}
22+
23+
const storedNetwork = localStorage.getItem(NETWORK_STORAGE_KEY);
24+
if (storedNetwork && ['mainnet', 'testnet', 'teratestnet', 'tstn'].includes(storedNetwork)) {
25+
return storedNetwork as Network;
26+
}
27+
28+
return 'mainnet';
29+
};
30+
31+
const [selectedNetwork, setSelectedNetwork] = useState<Network>(getInitialNetwork());
1232
const [nodeStatuses, setNodeStatuses] = useState<NodeStatusWithScore[]>([]);
1333
const [isLoading, setIsLoading] = useState(true);
1434
const [error, setError] = useState<string | null>(null);
@@ -17,6 +37,25 @@ const Networks: React.FC = () => {
1737
const [sortDirection, setSortDirection] = useState<'asc' | 'desc'>('desc');
1838
const [recentlyUpdated, setRecentlyUpdated] = useState<Set<string>>(new Set());
1939

40+
// Handle network change
41+
const handleNetworkChange = useCallback((network: Network) => {
42+
setSelectedNetwork(network);
43+
// Update URL query parameter
44+
setSearchParams({ network });
45+
// Store in localStorage
46+
localStorage.setItem(NETWORK_STORAGE_KEY, network);
47+
}, [setSearchParams]);
48+
49+
// Sync with URL changes (browser back/forward)
50+
useEffect(() => {
51+
const urlNetwork = searchParams.get('network');
52+
if (urlNetwork && ['mainnet', 'testnet', 'teratestnet', 'tstn'].includes(urlNetwork)) {
53+
const network = urlNetwork as Network;
54+
setSelectedNetwork(network);
55+
localStorage.setItem(NETWORK_STORAGE_KEY, network);
56+
}
57+
}, [searchParams]);
58+
2059
// WebSocket message handler
2160
const handleWebSocketMessage = useCallback((message: Message) => {
2261
// Check if it's a node_status message
@@ -258,7 +297,7 @@ const Networks: React.FC = () => {
258297
<div className="flex items-center gap-4">
259298
<select
260299
value={selectedNetwork}
261-
onChange={(e) => setSelectedNetwork(e.target.value as Network)}
300+
onChange={(e) => handleNetworkChange(e.target.value as Network)}
262301
className="px-4 py-2 bg-white border border-gray-300 rounded-lg shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500"
263302
>
264303
<option value="mainnet">Mainnet</option>

frontend-react/src/components/PeerDetail.tsx

Lines changed: 56 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -124,8 +124,9 @@ const PeerDetail: React.FC = () => {
124124
block: '📦',
125125
// miningon: '⛏️', // Temporarily disabled
126126
subtree: '🌳',
127-
handshake: '🤝',
127+
// handshake: '🤝', // Deprecated
128128
rejected_tx: '❌',
129+
node_status: '🖥️',
129130
bestblock: '🏆'
130131
};
131132
return icons[type] || '📄';
@@ -324,46 +325,75 @@ const PeerDetail: React.FC = () => {
324325
</div>
325326
</div>
326327

327-
{/* Recent Handshakes */}
328-
{peerDetail.handshakes.length > 0 && (
328+
{/* Recent Node Status Updates */}
329+
{peerDetail.nodeStatuses && peerDetail.nodeStatuses.length > 0 && (
329330
<div className="bg-white/80 backdrop-blur-xl rounded-2xl shadow-xl border border-white/50 p-6 sm:p-8 mb-8">
330331
<div className="flex items-center gap-3 mb-6">
331332
<div className="w-10 h-10 bg-gradient-to-br from-blue-500 to-cyan-600 rounded-xl flex items-center justify-center">
332-
<span className="text-2xl">🤝</span>
333+
<span className="text-2xl">🖥️</span>
333334
</div>
334-
<h2 className="text-xl font-semibold text-gray-900">Recent Handshakes</h2>
335+
<h2 className="text-xl font-semibold text-gray-900">Recent Node Status</h2>
335336
</div>
336-
337+
337338
<div className="overflow-hidden rounded-xl border border-gray-200">
338339
<div className="overflow-x-auto">
339340
<table className="min-w-full divide-y divide-gray-200">
340341
<thead className="bg-gradient-to-r from-gray-50 to-gray-100">
341342
<tr>
342-
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Type</th>
343-
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">User Agent</th>
343+
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">FSM State</th>
344+
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Client / Version</th>
344345
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Best Height</th>
346+
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Uptime</th>
345347
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Time</th>
346348
</tr>
347349
</thead>
348350
<tbody className="bg-white divide-y divide-gray-200">
349-
{peerDetail.handshakes.map((handshake, idx) => (
350-
<tr key={idx} className="hover:bg-gray-50 transition-colors duration-150">
351-
<td className="px-6 py-4 whitespace-nowrap">
352-
<span className="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-blue-100 text-blue-800">
353-
{handshake.Type}
354-
</span>
355-
</td>
356-
<td className="px-6 py-4 text-sm text-gray-600 max-w-xs truncate" title={handshake.UserAgent}>
357-
{handshake.UserAgent}
358-
</td>
359-
<td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">
360-
{handshake.BestHeight.toLocaleString()}
361-
</td>
362-
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
363-
{formatTime(handshake.ReceivedAt)}
364-
</td>
365-
</tr>
366-
))}
351+
{peerDetail.nodeStatuses.map((status, idx) => {
352+
const getFSMStateColor = (state: string) => {
353+
switch(state?.toUpperCase()) {
354+
case 'RUNNING': return 'bg-green-100 text-green-800';
355+
case 'CATCHINGBLOCKS': return 'bg-orange-100 text-orange-800';
356+
case 'LEGACYSYNC': return 'bg-yellow-100 text-yellow-800';
357+
case 'IDLE': return 'bg-gray-100 text-gray-800';
358+
default: return 'bg-blue-100 text-blue-800';
359+
}
360+
};
361+
362+
const formatUptime = (seconds: number) => {
363+
if (!seconds || seconds <= 0) return 'N/A';
364+
const days = Math.floor(seconds / 86400);
365+
const hours = Math.floor((seconds % 86400) / 3600);
366+
const minutes = Math.floor((seconds % 3600) / 60);
367+
if (days > 0) return `${days}d ${hours}h`;
368+
if (hours > 0) return `${hours}h ${minutes}m`;
369+
return `${minutes}m`;
370+
};
371+
372+
return (
373+
<tr key={idx} className="hover:bg-gray-50 transition-colors duration-150">
374+
<td className="px-6 py-4 whitespace-nowrap">
375+
<span className={`inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium ${getFSMStateColor(status.FSMState)}`}>
376+
{status.FSMState || 'UNKNOWN'}
377+
</span>
378+
</td>
379+
<td className="px-6 py-4 text-sm text-gray-600">
380+
<div>
381+
<div className="font-medium">{status.ClientName || 'Unknown'}</div>
382+
<div className="text-xs text-gray-500">{status.Version || 'N/A'}</div>
383+
</div>
384+
</td>
385+
<td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">
386+
{status.BestHeight?.toLocaleString() || 'N/A'}
387+
</td>
388+
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-600">
389+
{formatUptime(status.Uptime)}
390+
</td>
391+
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
392+
{formatTime(status.ReceivedAt)}
393+
</td>
394+
</tr>
395+
);
396+
})}
367397
</tbody>
368398
</table>
369399
</div>

frontend-react/src/components/Peers.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ const Peers: React.FC = () => {
7878
case 'subtree': return '🌳';
7979
case 'handshake': return '🤝';
8080
case 'rejected_tx': return '❌';
81+
case 'node_status': return '🖥️';
8182
case 'bestblock': return '🏆';
8283
default: return '📦';
8384
}

frontend-react/src/components/Stats.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ const Stats: React.FC = () => {
6767
case 'subtree': return '🌳';
6868
case 'handshake': return '🤝';
6969
case 'rejected_tx': return '❌';
70+
case 'node_status': return '🖥️';
7071
case 'bestblock': return '🏆';
7172
default: return '📦';
7273
}

frontend-react/src/services/api.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -278,8 +278,6 @@ export class ApiService {
278278
// return await this.getMiningMessages(filters);
279279
case 'subtree':
280280
return await this.getSubtrees(filters);
281-
case 'handshake':
282-
return await this.getHandshakes(filters);
283281
case 'rejected_tx':
284282
return await this.getRejectedTransactions(filters);
285283
case 'node_status':

frontend-react/src/types/Message.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ export interface PeerDetail {
8282
networks: string[];
8383
messageTypes: Record<string, number>;
8484
handshakes: Handshake[];
85+
nodeStatuses: NodeStatus[];
8586
recentBlocks: Block[];
8687
recentMining: MiningOn[];
8788
timeStats: {
@@ -213,7 +214,7 @@ export interface NodeStatus {
213214

214215
// Temporarily removing 'miningon' from visible message types
215216
// export type MessageType = 'block' | 'miningon' | 'subtree' | 'handshake' | 'rejected_tx' | 'node_status';
216-
export type MessageType = 'block' | 'subtree' | 'handshake' | 'rejected_tx' | 'node_status';
217+
export type MessageType = 'block' | 'subtree' | 'rejected_tx' | 'node_status';
217218
export type Network = 'mainnet' | 'testnet' | 'regtest' | 'stn' | 'teratestnet' | 'tstn';
218219

219220
export interface DashboardFilters {

0 commit comments

Comments
 (0)