@aaronbassett/midnight-local-devnet 0.1.1 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +44 -5
- package/dist/cli/commands/dashboard.d.ts +3 -0
- package/dist/cli/commands/dashboard.js +20 -0
- package/dist/cli/commands/dashboard.js.map +1 -0
- package/dist/cli/commands/interactive.d.ts +3 -0
- package/dist/cli/commands/interactive.js +16 -0
- package/dist/cli/commands/interactive.js.map +1 -0
- package/dist/cli/dashboard/app.d.ts +9 -0
- package/dist/cli/dashboard/app.js +106 -0
- package/dist/cli/dashboard/app.js.map +1 -0
- package/dist/cli/dashboard/components/gauge.d.ts +9 -0
- package/dist/cli/dashboard/components/gauge.js +10 -0
- package/dist/cli/dashboard/components/gauge.js.map +1 -0
- package/dist/cli/dashboard/components/panel-box.d.ts +10 -0
- package/dist/cli/dashboard/components/panel-box.js +6 -0
- package/dist/cli/dashboard/components/panel-box.js.map +1 -0
- package/dist/cli/dashboard/components/sparkline.d.ts +9 -0
- package/dist/cli/dashboard/components/sparkline.js +25 -0
- package/dist/cli/dashboard/components/sparkline.js.map +1 -0
- package/dist/cli/dashboard/components/status-badge.d.ts +6 -0
- package/dist/cli/dashboard/components/status-badge.js +24 -0
- package/dist/cli/dashboard/components/status-badge.js.map +1 -0
- package/dist/cli/dashboard/hooks/use-breakpoint.d.ts +7 -0
- package/dist/cli/dashboard/hooks/use-breakpoint.js +15 -0
- package/dist/cli/dashboard/hooks/use-breakpoint.js.map +1 -0
- package/dist/cli/dashboard/hooks/use-health.d.ts +9 -0
- package/dist/cli/dashboard/hooks/use-health.js +35 -0
- package/dist/cli/dashboard/hooks/use-health.js.map +1 -0
- package/dist/cli/dashboard/hooks/use-indexer-info.d.ts +5 -0
- package/dist/cli/dashboard/hooks/use-indexer-info.js +19 -0
- package/dist/cli/dashboard/hooks/use-indexer-info.js.map +1 -0
- package/dist/cli/dashboard/hooks/use-logs.d.ts +19 -0
- package/dist/cli/dashboard/hooks/use-logs.js +55 -0
- package/dist/cli/dashboard/hooks/use-logs.js.map +1 -0
- package/dist/cli/dashboard/hooks/use-node-info.d.ts +21 -0
- package/dist/cli/dashboard/hooks/use-node-info.js +49 -0
- package/dist/cli/dashboard/hooks/use-node-info.js.map +1 -0
- package/dist/cli/dashboard/hooks/use-polling.d.ts +7 -0
- package/dist/cli/dashboard/hooks/use-polling.js +35 -0
- package/dist/cli/dashboard/hooks/use-polling.js.map +1 -0
- package/dist/cli/dashboard/hooks/use-proof-server.d.ts +7 -0
- package/dist/cli/dashboard/hooks/use-proof-server.js +14 -0
- package/dist/cli/dashboard/hooks/use-proof-server.js.map +1 -0
- package/dist/cli/dashboard/hooks/use-services.d.ts +3 -0
- package/dist/cli/dashboard/hooks/use-services.js +6 -0
- package/dist/cli/dashboard/hooks/use-services.js.map +1 -0
- package/dist/cli/dashboard/hooks/use-terminal-size.d.ts +5 -0
- package/dist/cli/dashboard/hooks/use-terminal-size.js +22 -0
- package/dist/cli/dashboard/hooks/use-terminal-size.js.map +1 -0
- package/dist/cli/dashboard/hooks/use-wallet-state.d.ts +10 -0
- package/dist/cli/dashboard/hooks/use-wallet-state.js +63 -0
- package/dist/cli/dashboard/hooks/use-wallet-state.js.map +1 -0
- package/dist/cli/dashboard/layouts/large.d.ts +7 -0
- package/dist/cli/dashboard/layouts/large.js +13 -0
- package/dist/cli/dashboard/layouts/large.js.map +1 -0
- package/dist/cli/dashboard/layouts/medium.d.ts +7 -0
- package/dist/cli/dashboard/layouts/medium.js +11 -0
- package/dist/cli/dashboard/layouts/medium.js.map +1 -0
- package/dist/cli/dashboard/layouts/small.d.ts +7 -0
- package/dist/cli/dashboard/layouts/small.js +11 -0
- package/dist/cli/dashboard/layouts/small.js.map +1 -0
- package/dist/cli/dashboard/lib/log-parser.d.ts +15 -0
- package/dist/cli/dashboard/lib/log-parser.js +44 -0
- package/dist/cli/dashboard/lib/log-parser.js.map +1 -0
- package/dist/cli/dashboard/lib/proof-server-api.d.ts +15 -0
- package/dist/cli/dashboard/lib/proof-server-api.js +48 -0
- package/dist/cli/dashboard/lib/proof-server-api.js.map +1 -0
- package/dist/cli/dashboard/lib/substrate-rpc.d.ts +16 -0
- package/dist/cli/dashboard/lib/substrate-rpc.js +39 -0
- package/dist/cli/dashboard/lib/substrate-rpc.js.map +1 -0
- package/dist/cli/dashboard/panels/indexer-panel.d.ts +11 -0
- package/dist/cli/dashboard/panels/indexer-panel.js +17 -0
- package/dist/cli/dashboard/panels/indexer-panel.js.map +1 -0
- package/dist/cli/dashboard/panels/log-panel.d.ts +13 -0
- package/dist/cli/dashboard/panels/log-panel.js +27 -0
- package/dist/cli/dashboard/panels/log-panel.js.map +1 -0
- package/dist/cli/dashboard/panels/node-panel.d.ts +10 -0
- package/dist/cli/dashboard/panels/node-panel.js +17 -0
- package/dist/cli/dashboard/panels/node-panel.js.map +1 -0
- package/dist/cli/dashboard/panels/proof-panel.d.ts +10 -0
- package/dist/cli/dashboard/panels/proof-panel.js +20 -0
- package/dist/cli/dashboard/panels/proof-panel.js.map +1 -0
- package/dist/cli/dashboard/panels/response-graph.d.ts +10 -0
- package/dist/cli/dashboard/panels/response-graph.js +12 -0
- package/dist/cli/dashboard/panels/response-graph.js.map +1 -0
- package/dist/cli/dashboard/panels/wallet-panel.d.ts +9 -0
- package/dist/cli/dashboard/panels/wallet-panel.js +24 -0
- package/dist/cli/dashboard/panels/wallet-panel.js.map +1 -0
- package/dist/cli/dashboard/types.d.ts +39 -0
- package/dist/cli/dashboard/types.js +2 -0
- package/dist/cli/dashboard/types.js.map +1 -0
- package/dist/cli/interactive.js +123 -37
- package/dist/cli/interactive.js.map +1 -1
- package/dist/cli.js +10 -15
- package/dist/cli.js.map +1 -1
- package/dist/core/logger.d.ts +1 -1
- package/dist/core/logger.js +2 -1
- package/dist/core/logger.js.map +1 -1
- package/docker/standalone.yml +1 -1
- package/package.json +8 -4
package/README.md
CHANGED
|
@@ -13,16 +13,16 @@ A CLI and MCP (Model Context Protocol) server for managing a local Docker-based
|
|
|
13
13
|
|
|
14
14
|
### CLI
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
Start the network:
|
|
17
17
|
|
|
18
18
|
```bash
|
|
19
|
-
npx @aaronbassett/midnight-local-devnet
|
|
19
|
+
npx @aaronbassett/midnight-local-devnet start
|
|
20
20
|
```
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
Open the realtime dashboard in a second terminal pane to monitor your devnet:
|
|
23
23
|
|
|
24
24
|
```bash
|
|
25
|
-
npx @aaronbassett/midnight-local-devnet
|
|
25
|
+
npx @aaronbassett/midnight-local-devnet dashboard
|
|
26
26
|
```
|
|
27
27
|
|
|
28
28
|
### MCP Server
|
|
@@ -58,9 +58,48 @@ All commands can be run via `npx @aaronbassett/midnight-local-devnet <command>`.
|
|
|
58
58
|
| `fund <address>` | Fund a Bech32 address with NIGHT tokens | `--amount <n>` Amount in NIGHT (default: 50,000) |
|
|
59
59
|
| `fund-file <path>` | Fund all accounts from an accounts.json file | |
|
|
60
60
|
| `generate-accounts` | Generate random test accounts | `--count <n>`, `--format <mnemonic\|privateKey>`, `--output <path>`, `--fund`, `--register-dust` |
|
|
61
|
+
| `dashboard` | Open realtime terminal dashboard | |
|
|
61
62
|
| `interactive` | Start interactive menu mode | |
|
|
62
63
|
|
|
63
|
-
Running with no arguments
|
|
64
|
+
Running with no arguments displays help.
|
|
65
|
+
|
|
66
|
+
## Dashboard
|
|
67
|
+
|
|
68
|
+
The `dashboard` command opens a realtime terminal UI that displays the state of all local devnet services. It's designed to run in a side terminal pane while you develop.
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
npx @aaronbassett/midnight-local-devnet dashboard
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
The dashboard shows:
|
|
75
|
+
|
|
76
|
+
- **Node** -- Block height, average block time, chain, peers, sync status, version
|
|
77
|
+
- **Indexer** -- Indexed block height, lag vs node, readiness
|
|
78
|
+
- **Proof Server** -- Version, proof versions, job processing/pending/capacity
|
|
79
|
+
- **Wallet** -- Master wallet NIGHT (unshielded + shielded) and DUST balances
|
|
80
|
+
- **Logs** -- Combined color-coded log stream from all services, filterable by service, level, or substring search
|
|
81
|
+
- **Response Times** -- Sparkline charts of per-service response times (large terminals only)
|
|
82
|
+
|
|
83
|
+
The layout adapts to your terminal width:
|
|
84
|
+
|
|
85
|
+
| Terminal Width | Layout |
|
|
86
|
+
|---|---|
|
|
87
|
+
| < 40 columns | Single column, compact |
|
|
88
|
+
| 40--119 columns | Two-column grid |
|
|
89
|
+
| 120+ columns | Three-column with response time graphs |
|
|
90
|
+
|
|
91
|
+
Keyboard shortcuts:
|
|
92
|
+
|
|
93
|
+
| Key | Action |
|
|
94
|
+
|---|---|
|
|
95
|
+
| Tab | Cycle focus between panels |
|
|
96
|
+
| Up/Down | Scroll logs (when focused) |
|
|
97
|
+
| `s` | Cycle log service filter |
|
|
98
|
+
| `l` | Cycle log level filter |
|
|
99
|
+
| `/` | Enter log search mode |
|
|
100
|
+
| `q` | Exit dashboard |
|
|
101
|
+
|
|
102
|
+
The dashboard starts regardless of whether the network is running. Panels show "Connecting..." and update live when services come up.
|
|
64
103
|
|
|
65
104
|
## MCP Tool Reference
|
|
66
105
|
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export function registerDashboardCommand(program, manager) {
|
|
2
|
+
program
|
|
3
|
+
.command('dashboard')
|
|
4
|
+
.description('Open realtime terminal dashboard for the local devnet')
|
|
5
|
+
.action(async () => {
|
|
6
|
+
if (!process.stdin.isTTY) {
|
|
7
|
+
console.error('Error: Dashboard requires an interactive terminal (TTY).');
|
|
8
|
+
console.error('Run this command directly in a terminal, not through a pipe or script.');
|
|
9
|
+
process.exit(1);
|
|
10
|
+
}
|
|
11
|
+
// Dynamic import to avoid loading React/ink for non-dashboard commands
|
|
12
|
+
const { render } = await import('ink');
|
|
13
|
+
const React = await import('react');
|
|
14
|
+
const { App } = await import('../dashboard/app.js');
|
|
15
|
+
const { waitUntilExit } = render(React.createElement(App, { manager, config: manager.config }));
|
|
16
|
+
await waitUntilExit();
|
|
17
|
+
await manager.shutdown();
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=dashboard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dashboard.js","sourceRoot":"","sources":["../../../src/cli/commands/dashboard.ts"],"names":[],"mappings":"AAGA,MAAM,UAAU,wBAAwB,CAAC,OAAgB,EAAE,OAAuB;IAChF,OAAO;SACJ,OAAO,CAAC,WAAW,CAAC;SACpB,WAAW,CAAC,uDAAuD,CAAC;SACpE,MAAM,CAAC,KAAK,IAAI,EAAE;QACjB,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;YACzB,OAAO,CAAC,KAAK,CAAC,0DAA0D,CAAC,CAAC;YAC1E,OAAO,CAAC,KAAK,CAAC,wEAAwE,CAAC,CAAC;YACxF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,uEAAuE;QACvE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,CAAC;QACvC,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,CAAC;QACpC,MAAM,EAAE,GAAG,EAAE,GAAG,MAAM,MAAM,CAAC,qBAAqB,CAAC,CAAC;QAEpD,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,CAC9B,KAAK,CAAC,aAAa,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAC9D,CAAC;QAEF,MAAM,aAAa,EAAE,CAAC;QACtB,MAAM,OAAO,CAAC,QAAQ,EAAE,CAAC;IAC3B,CAAC,CAAC,CAAC;AACP,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { startInteractiveMode } from '../interactive.js';
|
|
2
|
+
export function registerInteractiveCommand(program, manager) {
|
|
3
|
+
program
|
|
4
|
+
.command('interactive')
|
|
5
|
+
.description('Start interactive menu mode')
|
|
6
|
+
.action(async () => {
|
|
7
|
+
try {
|
|
8
|
+
await startInteractiveMode(manager);
|
|
9
|
+
}
|
|
10
|
+
catch (error) {
|
|
11
|
+
console.error('Interactive mode error:', error instanceof Error ? error.message : error);
|
|
12
|
+
process.exit(1);
|
|
13
|
+
}
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=interactive.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interactive.js","sourceRoot":"","sources":["../../../src/cli/commands/interactive.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAEzD,MAAM,UAAU,0BAA0B,CAAC,OAAgB,EAAE,OAAuB;IAClF,OAAO;SACJ,OAAO,CAAC,aAAa,CAAC;SACtB,WAAW,CAAC,6BAA6B,CAAC;SAC1C,MAAM,CAAC,KAAK,IAAI,EAAE;QACjB,IAAI,CAAC;YACH,MAAM,oBAAoB,CAAC,OAAO,CAAC,CAAC;QACtC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,yBAAyB,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;YACzF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { NetworkManager } from '../../core/network-manager.js';
|
|
3
|
+
import type { NetworkConfig } from '../../core/types.js';
|
|
4
|
+
interface AppProps {
|
|
5
|
+
manager: NetworkManager;
|
|
6
|
+
config: NetworkConfig;
|
|
7
|
+
}
|
|
8
|
+
export declare function App({ manager, config }: AppProps): React.ReactElement;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import { Box, Text, useInput, useApp } from 'ink';
|
|
4
|
+
import { useBreakpoint } from './hooks/use-breakpoint.js';
|
|
5
|
+
import { useNodeInfo } from './hooks/use-node-info.js';
|
|
6
|
+
import { useProofServer } from './hooks/use-proof-server.js';
|
|
7
|
+
import { useHealth } from './hooks/use-health.js';
|
|
8
|
+
import { useIndexerInfo } from './hooks/use-indexer-info.js';
|
|
9
|
+
import { useWalletState } from './hooks/use-wallet-state.js';
|
|
10
|
+
import { useLogs } from './hooks/use-logs.js';
|
|
11
|
+
import { SmallLayout } from './layouts/small.js';
|
|
12
|
+
import { MediumLayout } from './layouts/medium.js';
|
|
13
|
+
import { LargeLayout } from './layouts/large.js';
|
|
14
|
+
const PANEL_CYCLE = ['node', 'indexer', 'proof', 'wallet', 'logs', 'graph'];
|
|
15
|
+
export function App({ manager, config }) {
|
|
16
|
+
const { exit } = useApp();
|
|
17
|
+
const { breakpoint, columns, rows } = useBreakpoint();
|
|
18
|
+
// Data hooks
|
|
19
|
+
const nodeInfo = useNodeInfo(config.node);
|
|
20
|
+
const proofServer = useProofServer(config.proofServer);
|
|
21
|
+
const health = useHealth(config);
|
|
22
|
+
const indexerInfo = useIndexerInfo(config.indexer);
|
|
23
|
+
const walletState = useWalletState(manager);
|
|
24
|
+
const logs = useLogs();
|
|
25
|
+
// UI state
|
|
26
|
+
const [focusedPanel, setFocusedPanel] = useState('node');
|
|
27
|
+
const [searchMode, setSearchMode] = useState(false);
|
|
28
|
+
const [searchText, setSearchText] = useState('');
|
|
29
|
+
const isInteractive = process.stdin.isTTY === true;
|
|
30
|
+
useInput((input, key) => {
|
|
31
|
+
if (searchMode) {
|
|
32
|
+
if (key.escape || key.return) {
|
|
33
|
+
setSearchMode(false);
|
|
34
|
+
if (key.return)
|
|
35
|
+
logs.setSearch(searchText);
|
|
36
|
+
if (key.escape) {
|
|
37
|
+
setSearchText('');
|
|
38
|
+
logs.setSearch('');
|
|
39
|
+
}
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
if (key.backspace || key.delete) {
|
|
43
|
+
setSearchText((prev) => prev.slice(0, -1));
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
setSearchText((prev) => prev + input);
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
if (input === 'q') {
|
|
50
|
+
exit();
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
if (key.tab) {
|
|
54
|
+
setFocusedPanel((prev) => {
|
|
55
|
+
const idx = PANEL_CYCLE.indexOf(prev);
|
|
56
|
+
return PANEL_CYCLE[(idx + 1) % PANEL_CYCLE.length];
|
|
57
|
+
});
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
if (input === 's') {
|
|
61
|
+
logs.cycleService();
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
if (input === 'l') {
|
|
65
|
+
logs.cycleLevel();
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
if (input === '/') {
|
|
69
|
+
setSearchMode(true);
|
|
70
|
+
setSearchText('');
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
if (key.upArrow) {
|
|
74
|
+
if (focusedPanel === 'logs')
|
|
75
|
+
logs.scrollUp();
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
if (key.downArrow) {
|
|
79
|
+
if (focusedPanel === 'logs')
|
|
80
|
+
logs.scrollDown();
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
}, { isActive: isInteractive });
|
|
84
|
+
const data = {
|
|
85
|
+
node: nodeInfo.data,
|
|
86
|
+
nodeLoading: nodeInfo.loading,
|
|
87
|
+
indexer: indexerInfo.data,
|
|
88
|
+
indexerLoading: indexerInfo.loading,
|
|
89
|
+
proofServer: proofServer.data,
|
|
90
|
+
proofServerLoading: proofServer.loading,
|
|
91
|
+
wallet: walletState,
|
|
92
|
+
logs,
|
|
93
|
+
healthHistory: {
|
|
94
|
+
nodeHistory: health.data?.nodeHistory ?? [],
|
|
95
|
+
indexerHistory: health.data?.indexerHistory ?? [],
|
|
96
|
+
proofServerHistory: health.data?.proofServerHistory ?? [],
|
|
97
|
+
},
|
|
98
|
+
focusedPanel,
|
|
99
|
+
searchMode,
|
|
100
|
+
searchText,
|
|
101
|
+
columns,
|
|
102
|
+
rows,
|
|
103
|
+
};
|
|
104
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { justifyContent: "space-between", children: [_jsx(Text, { bold: true, color: "cyan", children: "Midnight Local Devnet" }), _jsxs(Text, { color: "gray", children: [columns, "x", rows, " | ", breakpoint, " | Tab=focus q=quit s=svc l=lvl /=search"] })] }), breakpoint === 'small' && _jsx(SmallLayout, { data: data }), breakpoint === 'medium' && _jsx(MediumLayout, { data: data }), breakpoint === 'large' && _jsx(LargeLayout, { data: data })] }));
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=app.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app.js","sourceRoot":"","sources":["../../../src/cli/dashboard/app.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Text } from 'ink';
|
|
3
|
+
export function Gauge({ value, max, width = 10, label }) {
|
|
4
|
+
const filled = max > 0 ? Math.round((value / max) * width) : 0;
|
|
5
|
+
const empty = width - filled;
|
|
6
|
+
const percentage = max > 0 ? Math.round((value / max) * 100) : 0;
|
|
7
|
+
const color = percentage >= 90 ? 'red' : percentage >= 70 ? 'yellow' : 'green';
|
|
8
|
+
return (_jsxs(Text, { children: [_jsx(Text, { color: color, children: '█'.repeat(filled) }), _jsx(Text, { color: "gray", children: '░'.repeat(empty) }), _jsxs(Text, { children: [" ", value, "/", max] }), label ? _jsxs(Text, { children: [" ", label] }) : null] }));
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=gauge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gauge.js","sourceRoot":"","sources":["../../../../src/cli/dashboard/components/gauge.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAS3B,MAAM,UAAU,KAAK,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,GAAG,EAAE,EAAE,KAAK,EAAc;IACjE,MAAM,MAAM,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,GAAG,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/D,MAAM,KAAK,GAAG,KAAK,GAAG,MAAM,CAAC;IAC7B,MAAM,UAAU,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAEjE,MAAM,KAAK,GAAG,UAAU,IAAI,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC;IAE/E,OAAO,CACL,MAAC,IAAI,eACH,KAAC,IAAI,IAAC,KAAK,EAAE,KAAK,YAAG,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,GAAQ,EAC/C,KAAC,IAAI,IAAC,KAAK,EAAC,MAAM,YAAE,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,GAAQ,EAC7C,MAAC,IAAI,oBAAG,KAAK,OAAG,GAAG,IAAQ,EAC1B,KAAK,CAAC,CAAC,CAAC,MAAC,IAAI,oBAAG,KAAK,IAAQ,CAAC,CAAC,CAAC,IAAI,IAChC,CACR,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
interface PanelBoxProps {
|
|
3
|
+
title: string;
|
|
4
|
+
focused?: boolean;
|
|
5
|
+
width?: number | string;
|
|
6
|
+
height?: number;
|
|
7
|
+
children: React.ReactNode;
|
|
8
|
+
}
|
|
9
|
+
export declare function PanelBox({ title, focused, width, height, children }: PanelBoxProps): React.ReactElement;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Box, Text } from 'ink';
|
|
3
|
+
export function PanelBox({ title, focused, width, height, children }) {
|
|
4
|
+
return (_jsxs(Box, { flexDirection: "column", borderStyle: focused ? 'bold' : 'single', borderColor: focused ? 'cyan' : 'gray', width: width, height: height, paddingX: 1, children: [_jsx(Text, { bold: true, color: focused ? 'cyan' : 'white', children: title }), children] }));
|
|
5
|
+
}
|
|
6
|
+
//# sourceMappingURL=panel-box.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"panel-box.js","sourceRoot":"","sources":["../../../../src/cli/dashboard/components/panel-box.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAUhC,MAAM,UAAU,QAAQ,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAiB;IACjF,OAAO,CACL,MAAC,GAAG,IACF,aAAa,EAAC,QAAQ,EACtB,WAAW,EAAE,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,EACxC,WAAW,EAAE,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EACtC,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,CAAC,aAEX,KAAC,IAAI,IAAC,IAAI,QAAC,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,YACzC,KAAK,GACD,EACN,QAAQ,IACL,CACP,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export declare function renderSparkline(data: number[], maxWidth?: number): string;
|
|
3
|
+
interface SparklineProps {
|
|
4
|
+
data: number[];
|
|
5
|
+
maxWidth?: number;
|
|
6
|
+
color?: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function Sparkline({ data, maxWidth, color }: SparklineProps): React.ReactElement;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Text } from 'ink';
|
|
3
|
+
const BARS = ['▁', '▂', '▃', '▄', '▅', '▆', '▇', '█'];
|
|
4
|
+
export function renderSparkline(data, maxWidth) {
|
|
5
|
+
if (data.length === 0)
|
|
6
|
+
return '';
|
|
7
|
+
const values = maxWidth && data.length > maxWidth ? data.slice(-maxWidth) : data;
|
|
8
|
+
const min = Math.min(...values);
|
|
9
|
+
const max = Math.max(...values);
|
|
10
|
+
const range = max - min;
|
|
11
|
+
if (range === 0) {
|
|
12
|
+
const mid = Math.floor((BARS.length - 1) / 2);
|
|
13
|
+
return values.map(() => BARS[mid]).join('');
|
|
14
|
+
}
|
|
15
|
+
return values
|
|
16
|
+
.map((v) => {
|
|
17
|
+
const idx = Math.round(((v - min) / range) * (BARS.length - 1));
|
|
18
|
+
return BARS[idx];
|
|
19
|
+
})
|
|
20
|
+
.join('');
|
|
21
|
+
}
|
|
22
|
+
export function Sparkline({ data, maxWidth, color }) {
|
|
23
|
+
return _jsx(Text, { color: color, children: renderSparkline(data, maxWidth) });
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=sparkline.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sparkline.js","sourceRoot":"","sources":["../../../../src/cli/dashboard/components/sparkline.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAE3B,MAAM,IAAI,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAU,CAAC;AAE/D,MAAM,UAAU,eAAe,CAAC,IAAc,EAAE,QAAiB;IAC/D,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAEjC,MAAM,MAAM,GAAG,QAAQ,IAAI,IAAI,CAAC,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACjF,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC;IAChC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC;IAChC,MAAM,KAAK,GAAG,GAAG,GAAG,GAAG,CAAC;IAExB,IAAI,KAAK,KAAK,CAAC,EAAE,CAAC;QAChB,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QAC9C,OAAO,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC9C,CAAC;IAED,OAAO,MAAM;SACV,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QACT,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;QAChE,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;IACnB,CAAC,CAAC;SACD,IAAI,CAAC,EAAE,CAAC,CAAC;AACd,CAAC;AAQD,MAAM,UAAU,SAAS,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAkB;IACjE,OAAO,KAAC,IAAI,IAAC,KAAK,EAAE,KAAK,YAAG,eAAe,CAAC,IAAI,EAAE,QAAQ,CAAC,GAAQ,CAAC;AACtE,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Text } from 'ink';
|
|
3
|
+
const STATUS_COLORS = {
|
|
4
|
+
healthy: 'green',
|
|
5
|
+
running: 'green',
|
|
6
|
+
ok: 'green',
|
|
7
|
+
busy: 'yellow',
|
|
8
|
+
unknown: 'gray',
|
|
9
|
+
unhealthy: 'red',
|
|
10
|
+
stopped: 'red',
|
|
11
|
+
};
|
|
12
|
+
const STATUS_SYMBOLS = {
|
|
13
|
+
healthy: '●',
|
|
14
|
+
running: '●',
|
|
15
|
+
ok: '●',
|
|
16
|
+
busy: '◐',
|
|
17
|
+
unknown: '○',
|
|
18
|
+
unhealthy: '●',
|
|
19
|
+
stopped: '●',
|
|
20
|
+
};
|
|
21
|
+
export function StatusBadge({ status }) {
|
|
22
|
+
return (_jsxs(Text, { color: STATUS_COLORS[status], children: [STATUS_SYMBOLS[status], " ", status] }));
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=status-badge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status-badge.js","sourceRoot":"","sources":["../../../../src/cli/dashboard/components/status-badge.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAM3B,MAAM,aAAa,GAA+C;IAChE,OAAO,EAAE,OAAO;IAChB,OAAO,EAAE,OAAO;IAChB,EAAE,EAAE,OAAO;IACX,IAAI,EAAE,QAAQ;IACd,OAAO,EAAE,MAAM;IACf,SAAS,EAAE,KAAK;IAChB,OAAO,EAAE,KAAK;CACf,CAAC;AAEF,MAAM,cAAc,GAA+C;IACjE,OAAO,EAAE,GAAG;IACZ,OAAO,EAAE,GAAG;IACZ,EAAE,EAAE,GAAG;IACP,IAAI,EAAE,GAAG;IACT,OAAO,EAAE,GAAG;IACZ,SAAS,EAAE,GAAG;IACd,OAAO,EAAE,GAAG;CACb,CAAC;AAEF,MAAM,UAAU,WAAW,CAAC,EAAE,MAAM,EAAoB;IACtD,OAAO,CACL,MAAC,IAAI,IAAC,KAAK,EAAE,aAAa,CAAC,MAAM,CAAC,aAC/B,cAAc,CAAC,MAAM,CAAC,OAAG,MAAM,IAC3B,CACR,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { useMemo } from 'react';
|
|
2
|
+
import { useTerminalSize } from './use-terminal-size.js';
|
|
3
|
+
export function getBreakpoint(width) {
|
|
4
|
+
if (width < 40)
|
|
5
|
+
return 'small';
|
|
6
|
+
if (width < 120)
|
|
7
|
+
return 'medium';
|
|
8
|
+
return 'large';
|
|
9
|
+
}
|
|
10
|
+
export function useBreakpoint() {
|
|
11
|
+
const { columns, rows } = useTerminalSize();
|
|
12
|
+
const breakpoint = useMemo(() => getBreakpoint(columns), [columns]);
|
|
13
|
+
return { breakpoint, columns, rows };
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=use-breakpoint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-breakpoint.js","sourceRoot":"","sources":["../../../../src/cli/dashboard/hooks/use-breakpoint.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAChC,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAIzD,MAAM,UAAU,aAAa,CAAC,KAAa;IACzC,IAAI,KAAK,GAAG,EAAE;QAAE,OAAO,OAAO,CAAC;IAC/B,IAAI,KAAK,GAAG,GAAG;QAAE,OAAO,QAAQ,CAAC;IACjC,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,UAAU,aAAa;IAC3B,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,eAAe,EAAE,CAAC;IAC5C,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IACpE,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AACvC,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type HealthReport } from '../../../core/health.js';
|
|
2
|
+
import type { NetworkConfig } from '../../../core/types.js';
|
|
3
|
+
export interface HealthWithHistory {
|
|
4
|
+
current: HealthReport;
|
|
5
|
+
nodeHistory: number[];
|
|
6
|
+
indexerHistory: number[];
|
|
7
|
+
proofServerHistory: number[];
|
|
8
|
+
}
|
|
9
|
+
export declare function useHealth(config: NetworkConfig): import("./use-polling.js").PollingState<HealthWithHistory>;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { useRef } from 'react';
|
|
2
|
+
import { usePolling } from './use-polling.js';
|
|
3
|
+
import { checkAllHealth } from '../../../core/health.js';
|
|
4
|
+
const MAX_HISTORY = 30;
|
|
5
|
+
export function useHealth(config) {
|
|
6
|
+
const nodeHistory = useRef([]);
|
|
7
|
+
const indexerHistory = useRef([]);
|
|
8
|
+
const proofServerHistory = useRef([]);
|
|
9
|
+
const polling = usePolling(async () => {
|
|
10
|
+
const report = await checkAllHealth(config);
|
|
11
|
+
if (report.node.responseTime != null) {
|
|
12
|
+
nodeHistory.current.push(report.node.responseTime);
|
|
13
|
+
if (nodeHistory.current.length > MAX_HISTORY)
|
|
14
|
+
nodeHistory.current.shift();
|
|
15
|
+
}
|
|
16
|
+
if (report.indexer.responseTime != null) {
|
|
17
|
+
indexerHistory.current.push(report.indexer.responseTime);
|
|
18
|
+
if (indexerHistory.current.length > MAX_HISTORY)
|
|
19
|
+
indexerHistory.current.shift();
|
|
20
|
+
}
|
|
21
|
+
if (report.proofServer.responseTime != null) {
|
|
22
|
+
proofServerHistory.current.push(report.proofServer.responseTime);
|
|
23
|
+
if (proofServerHistory.current.length > MAX_HISTORY)
|
|
24
|
+
proofServerHistory.current.shift();
|
|
25
|
+
}
|
|
26
|
+
return {
|
|
27
|
+
current: report,
|
|
28
|
+
nodeHistory: [...nodeHistory.current],
|
|
29
|
+
indexerHistory: [...indexerHistory.current],
|
|
30
|
+
proofServerHistory: [...proofServerHistory.current],
|
|
31
|
+
};
|
|
32
|
+
}, 10000);
|
|
33
|
+
return polling;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=use-health.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-health.js","sourceRoot":"","sources":["../../../../src/cli/dashboard/hooks/use-health.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAqB,MAAM,yBAAyB,CAAC;AAU5E,MAAM,WAAW,GAAG,EAAE,CAAC;AAEvB,MAAM,UAAU,SAAS,CAAC,MAAqB;IAC7C,MAAM,WAAW,GAAG,MAAM,CAAW,EAAE,CAAC,CAAC;IACzC,MAAM,cAAc,GAAG,MAAM,CAAW,EAAE,CAAC,CAAC;IAC5C,MAAM,kBAAkB,GAAG,MAAM,CAAW,EAAE,CAAC,CAAC;IAEhD,MAAM,OAAO,GAAG,UAAU,CAAC,KAAK,IAAgC,EAAE;QAChE,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,MAAM,CAAC,CAAC;QAE5C,IAAI,MAAM,CAAC,IAAI,CAAC,YAAY,IAAI,IAAI,EAAE,CAAC;YACrC,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;YACnD,IAAI,WAAW,CAAC,OAAO,CAAC,MAAM,GAAG,WAAW;gBAAE,WAAW,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QAC5E,CAAC;QACD,IAAI,MAAM,CAAC,OAAO,CAAC,YAAY,IAAI,IAAI,EAAE,CAAC;YACxC,cAAc,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;YACzD,IAAI,cAAc,CAAC,OAAO,CAAC,MAAM,GAAG,WAAW;gBAAE,cAAc,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QAClF,CAAC;QACD,IAAI,MAAM,CAAC,WAAW,CAAC,YAAY,IAAI,IAAI,EAAE,CAAC;YAC5C,kBAAkB,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,YAAY,CAAC,CAAC;YACjE,IAAI,kBAAkB,CAAC,OAAO,CAAC,MAAM,GAAG,WAAW;gBAAE,kBAAkB,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QAC1F,CAAC;QAED,OAAO;YACL,OAAO,EAAE,MAAM;YACf,WAAW,EAAE,CAAC,GAAG,WAAW,CAAC,OAAO,CAAC;YACrC,cAAc,EAAE,CAAC,GAAG,cAAc,CAAC,OAAO,CAAC;YAC3C,kBAAkB,EAAE,CAAC,GAAG,kBAAkB,CAAC,OAAO,CAAC;SACpD,CAAC;IACJ,CAAC,EAAE,KAAK,CAAC,CAAC;IAEV,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { usePolling } from './use-polling.js';
|
|
2
|
+
async function fetchIndexerInfo(indexerUrl) {
|
|
3
|
+
const origin = new URL(indexerUrl).origin;
|
|
4
|
+
const start = Date.now();
|
|
5
|
+
try {
|
|
6
|
+
const response = await fetch(`${origin}/ready`, { signal: AbortSignal.timeout(5000) });
|
|
7
|
+
return {
|
|
8
|
+
ready: response.ok,
|
|
9
|
+
responseTime: Date.now() - start,
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
return { ready: false, responseTime: Date.now() - start };
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
export function useIndexerInfo(indexerUrl) {
|
|
17
|
+
return usePolling(() => fetchIndexerInfo(indexerUrl), 10000);
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=use-indexer-info.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-indexer-info.js","sourceRoot":"","sources":["../../../../src/cli/dashboard/hooks/use-indexer-info.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAO9C,KAAK,UAAU,gBAAgB,CAAC,UAAkB;IAChD,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC;IAC1C,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACzB,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,MAAM,QAAQ,EAAE,EAAE,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACvF,OAAO;YACL,KAAK,EAAE,QAAQ,CAAC,EAAE;YAClB,YAAY,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK;SACjC,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,YAAY,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,EAAE,CAAC;IAC5D,CAAC;AACH,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,UAAkB;IAC/C,OAAO,UAAU,CAAC,GAAG,EAAE,CAAC,gBAAgB,CAAC,UAAU,CAAC,EAAE,KAAK,CAAC,CAAC;AAC/D,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type ParsedLogLine, type LogFilter } from '../lib/log-parser.js';
|
|
2
|
+
export interface LogState {
|
|
3
|
+
lines: ParsedLogLine[];
|
|
4
|
+
filteredLines: ParsedLogLine[];
|
|
5
|
+
filter: LogFilter;
|
|
6
|
+
scrollOffset: number;
|
|
7
|
+
}
|
|
8
|
+
export declare function useLogs(): {
|
|
9
|
+
lines: ParsedLogLine[];
|
|
10
|
+
allLines: ParsedLogLine[];
|
|
11
|
+
filter: LogFilter;
|
|
12
|
+
scrollOffset: number;
|
|
13
|
+
loading: boolean;
|
|
14
|
+
cycleService: () => void;
|
|
15
|
+
cycleLevel: () => void;
|
|
16
|
+
setSearch: (search: string) => void;
|
|
17
|
+
scrollUp: () => void;
|
|
18
|
+
scrollDown: () => void;
|
|
19
|
+
};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { useState, useCallback } from 'react';
|
|
2
|
+
import { usePolling } from './use-polling.js';
|
|
3
|
+
import { composeLogs } from '../../../core/docker.js';
|
|
4
|
+
import { parseLogLines, filterLogs } from '../lib/log-parser.js';
|
|
5
|
+
const SERVICE_CYCLE = [undefined, 'node', 'indexer', 'proof-server'];
|
|
6
|
+
const LEVEL_CYCLE = [undefined, 'info', 'warn', 'error'];
|
|
7
|
+
export function useLogs() {
|
|
8
|
+
const [filter, setFilter] = useState({});
|
|
9
|
+
const [scrollOffset, setScrollOffset] = useState(0);
|
|
10
|
+
const polling = usePolling(async () => {
|
|
11
|
+
const raw = await composeLogs({ lines: 100 });
|
|
12
|
+
return parseLogLines(raw);
|
|
13
|
+
}, 3000);
|
|
14
|
+
const lines = polling.data ?? [];
|
|
15
|
+
const filteredLines = filterLogs(lines, filter);
|
|
16
|
+
const cycleService = useCallback(() => {
|
|
17
|
+
setFilter((prev) => {
|
|
18
|
+
const currentIdx = SERVICE_CYCLE.indexOf(prev.service);
|
|
19
|
+
const nextIdx = (currentIdx + 1) % SERVICE_CYCLE.length;
|
|
20
|
+
return { ...prev, service: SERVICE_CYCLE[nextIdx] };
|
|
21
|
+
});
|
|
22
|
+
setScrollOffset(0);
|
|
23
|
+
}, []);
|
|
24
|
+
const cycleLevel = useCallback(() => {
|
|
25
|
+
setFilter((prev) => {
|
|
26
|
+
const currentIdx = LEVEL_CYCLE.indexOf(prev.level);
|
|
27
|
+
const nextIdx = (currentIdx + 1) % LEVEL_CYCLE.length;
|
|
28
|
+
return { ...prev, level: LEVEL_CYCLE[nextIdx] };
|
|
29
|
+
});
|
|
30
|
+
setScrollOffset(0);
|
|
31
|
+
}, []);
|
|
32
|
+
const setSearch = useCallback((search) => {
|
|
33
|
+
setFilter((prev) => ({ ...prev, search: search || undefined }));
|
|
34
|
+
setScrollOffset(0);
|
|
35
|
+
}, []);
|
|
36
|
+
const scrollUp = useCallback(() => {
|
|
37
|
+
setScrollOffset((prev) => Math.max(0, prev - 1));
|
|
38
|
+
}, []);
|
|
39
|
+
const scrollDown = useCallback(() => {
|
|
40
|
+
setScrollOffset((prev) => Math.min(filteredLines.length - 1, prev + 1));
|
|
41
|
+
}, [filteredLines.length]);
|
|
42
|
+
return {
|
|
43
|
+
lines: filteredLines,
|
|
44
|
+
allLines: lines,
|
|
45
|
+
filter,
|
|
46
|
+
scrollOffset,
|
|
47
|
+
loading: polling.loading,
|
|
48
|
+
cycleService,
|
|
49
|
+
cycleLevel,
|
|
50
|
+
setSearch,
|
|
51
|
+
scrollUp,
|
|
52
|
+
scrollDown,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=use-logs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-logs.js","sourceRoot":"","sources":["../../../../src/cli/dashboard/hooks/use-logs.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type SystemHealth } from '../lib/substrate-rpc.js';
|
|
2
|
+
export interface NodeInfo {
|
|
3
|
+
chainName: string | null;
|
|
4
|
+
nodeName: string | null;
|
|
5
|
+
version: string | null;
|
|
6
|
+
health: SystemHealth | null;
|
|
7
|
+
bestBlock: number | null;
|
|
8
|
+
avgBlockTime: number | null;
|
|
9
|
+
}
|
|
10
|
+
export declare function useNodeInfo(nodeUrl: string): {
|
|
11
|
+
data: {
|
|
12
|
+
avgBlockTime: number | null;
|
|
13
|
+
chainName: string | null;
|
|
14
|
+
nodeName: string | null;
|
|
15
|
+
version: string | null;
|
|
16
|
+
health: SystemHealth | null;
|
|
17
|
+
bestBlock: number | null;
|
|
18
|
+
} | null;
|
|
19
|
+
error: unknown | null;
|
|
20
|
+
loading: boolean;
|
|
21
|
+
};
|