@silvery/examples 0.17.3 → 0.17.5
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/dist/UPNG-ShUlaTDh.mjs +5074 -0
- package/dist/__vite-browser-external-2447137e-Bopa5BFR.mjs +4 -0
- package/dist/_banner-A70_y2Vi.mjs +43 -0
- package/dist/ansi-0VXlUmNn.mjs +16397 -0
- package/dist/apng-B0gRaDVT.mjs +3 -0
- package/dist/apng-BTRDTfDW.mjs +68 -0
- package/dist/apps/aichat/index.mjs +1298 -0
- package/dist/apps/app-todo.mjs +138 -0
- package/dist/apps/async-data.mjs +203 -0
- package/dist/apps/cli-wizard.mjs +338 -0
- package/dist/apps/clipboard.mjs +197 -0
- package/dist/apps/components.mjs +863 -0
- package/dist/apps/data-explorer.mjs +482 -0
- package/dist/apps/dev-tools.mjs +396 -0
- package/dist/apps/explorer.mjs +697 -0
- package/dist/apps/gallery.mjs +765 -0
- package/dist/apps/inline-bench.mjs +115 -0
- package/dist/apps/kanban.mjs +279 -0
- package/dist/apps/layout-ref.mjs +186 -0
- package/dist/apps/outline.mjs +202 -0
- package/dist/apps/paste-demo.mjs +188 -0
- package/dist/apps/scroll.mjs +85 -0
- package/dist/apps/search-filter.mjs +286 -0
- package/dist/apps/selection.mjs +354 -0
- package/dist/apps/spatial-focus-demo.mjs +387 -0
- package/dist/apps/task-list.mjs +257 -0
- package/dist/apps/terminal-caps-demo.mjs +314 -0
- package/dist/apps/terminal.mjs +871 -0
- package/dist/apps/text-selection-demo.mjs +253 -0
- package/dist/apps/textarea.mjs +177 -0
- package/dist/apps/theme.mjs +660 -0
- package/dist/apps/transform.mjs +214 -0
- package/dist/apps/virtual-10k.mjs +421 -0
- package/dist/assets/resvgjs.darwin-arm64-BtufyGW1.node +0 -0
- package/dist/backends-Dj-11kZF.mjs +1179 -0
- package/dist/backends-U3QwStfO.mjs +3 -0
- package/dist/{cli.mjs → bin/cli.mjs} +15 -19
- package/dist/chunk-BSw8zbkd.mjs +37 -0
- package/dist/components/counter.mjs +47 -0
- package/dist/components/hello.mjs +30 -0
- package/dist/components/progress-bar.mjs +58 -0
- package/dist/components/select-list.mjs +84 -0
- package/dist/components/spinner.mjs +56 -0
- package/dist/components/text-input.mjs +61 -0
- package/dist/components/virtual-list.mjs +50 -0
- package/dist/flexily-zero-adapter-ByVzLTFP.mjs +3374 -0
- package/dist/gif-B6NGH5gs.mjs +3 -0
- package/dist/gif-CfkOF-iG.mjs +71 -0
- package/dist/gifenc-BI4ihP_T.mjs +728 -0
- package/dist/key-mapping-5oYQdAQE.mjs +3 -0
- package/dist/key-mapping-D4LR1go6.mjs +130 -0
- package/dist/layout/dashboard.mjs +1203 -0
- package/dist/layout/live-resize.mjs +302 -0
- package/dist/layout/overflow.mjs +69 -0
- package/dist/layout/text-layout.mjs +334 -0
- package/dist/node-nsrAOjH4.mjs +1083 -0
- package/dist/plugins-CT0DdV_E.mjs +3056 -0
- package/dist/resvg-js-Cnk2o49d.mjs +201 -0
- package/dist/src-9ZhfQyzD.mjs +814 -0
- package/dist/src-CUUOuRH6.mjs +5322 -0
- package/dist/src-jO3Zuzjj.mjs +23538 -0
- package/dist/usingCtx-CsEf0xO3.mjs +57 -0
- package/dist/yoga-adapter-BSQHuMV9.mjs +237 -0
- package/package.json +21 -14
- package/_banner.tsx +0 -60
- package/apps/aichat/components.tsx +0 -469
- package/apps/aichat/index.tsx +0 -220
- package/apps/aichat/script.ts +0 -460
- package/apps/aichat/state.ts +0 -325
- package/apps/aichat/types.ts +0 -19
- package/apps/app-todo.tsx +0 -201
- package/apps/async-data.tsx +0 -196
- package/apps/cli-wizard.tsx +0 -332
- package/apps/clipboard.tsx +0 -183
- package/apps/components.tsx +0 -658
- package/apps/data-explorer.tsx +0 -490
- package/apps/dev-tools.tsx +0 -395
- package/apps/explorer.tsx +0 -731
- package/apps/gallery.tsx +0 -653
- package/apps/inline-bench.tsx +0 -138
- package/apps/kanban.tsx +0 -265
- package/apps/layout-ref.tsx +0 -173
- package/apps/outline.tsx +0 -160
- package/apps/panes/index.tsx +0 -203
- package/apps/paste-demo.tsx +0 -185
- package/apps/scroll.tsx +0 -80
- package/apps/search-filter.tsx +0 -240
- package/apps/selection.tsx +0 -346
- package/apps/spatial-focus-demo.tsx +0 -372
- package/apps/task-list.tsx +0 -271
- package/apps/terminal-caps-demo.tsx +0 -317
- package/apps/terminal.tsx +0 -784
- package/apps/text-selection-demo.tsx +0 -193
- package/apps/textarea.tsx +0 -155
- package/apps/theme.tsx +0 -515
- package/apps/transform.tsx +0 -229
- package/apps/virtual-10k.tsx +0 -405
- package/apps/vterm-demo/index.tsx +0 -216
- package/components/counter.tsx +0 -49
- package/components/hello.tsx +0 -38
- package/components/progress-bar.tsx +0 -52
- package/components/select-list.tsx +0 -54
- package/components/spinner.tsx +0 -44
- package/components/text-input.tsx +0 -61
- package/components/virtual-list.tsx +0 -56
- package/dist/cli.d.mts +0 -1
- package/dist/cli.mjs.map +0 -1
- package/layout/dashboard.tsx +0 -953
- package/layout/live-resize.tsx +0 -282
- package/layout/overflow.tsx +0 -51
- package/layout/text-layout.tsx +0 -283
package/layout/dashboard.tsx
DELETED
|
@@ -1,953 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Dashboard Example
|
|
3
|
-
*
|
|
4
|
-
* A btop-style responsive dashboard demonstrating:
|
|
5
|
-
* - Multi-pane flexbox layout with round borders
|
|
6
|
-
* - Live-updating metrics with sparklines and progress bars
|
|
7
|
-
* - Responsive 2-column / tabbed layout via useBoxRect()
|
|
8
|
-
* - Semantic theme colors with severity-based color coding
|
|
9
|
-
* - Process table with sorting
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
import React, { useState } from "react"
|
|
13
|
-
import {
|
|
14
|
-
render,
|
|
15
|
-
Box,
|
|
16
|
-
Text,
|
|
17
|
-
Muted,
|
|
18
|
-
Tabs,
|
|
19
|
-
TabList,
|
|
20
|
-
Tab,
|
|
21
|
-
TabPanel,
|
|
22
|
-
useBoxRect,
|
|
23
|
-
useInput,
|
|
24
|
-
useApp,
|
|
25
|
-
useInterval,
|
|
26
|
-
createTerm,
|
|
27
|
-
type Key,
|
|
28
|
-
} from "silvery"
|
|
29
|
-
import { ExampleBanner, type ExampleMeta } from "../_banner.js"
|
|
30
|
-
|
|
31
|
-
export const meta: ExampleMeta = {
|
|
32
|
-
name: "Dashboard",
|
|
33
|
-
description: "Responsive multi-pane dashboard with live metrics and charts",
|
|
34
|
-
demo: true,
|
|
35
|
-
features: ["Box flexGrow", "useBoxRect()", "responsive", "live data", "sparklines"],
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// ============================================================================
|
|
39
|
-
// Sparkline
|
|
40
|
-
// ============================================================================
|
|
41
|
-
|
|
42
|
-
const SPARK_CHARS = "▁▂▃▄▅▆▇█"
|
|
43
|
-
|
|
44
|
-
function sparkline(values: number[]): string {
|
|
45
|
-
return values.map((v) => SPARK_CHARS[Math.max(0, Math.min(7, v))] ?? SPARK_CHARS[0]).join("")
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/** Fixed-width inline progress bar string: ████████░░░░ */
|
|
49
|
-
function miniBar(pct: number, width: number): string {
|
|
50
|
-
const filled = Math.round((pct / 100) * width)
|
|
51
|
-
return "█".repeat(filled) + "░".repeat(width - filled)
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// ============================================================================
|
|
55
|
-
// Data Helpers
|
|
56
|
-
// ============================================================================
|
|
57
|
-
|
|
58
|
-
function jitter(base: number, range: number): number {
|
|
59
|
-
return Math.max(0, Math.min(100, base + (Math.random() - 0.5) * range))
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
function pushHistory(history: number[], value: number, max = 20): number[] {
|
|
63
|
-
const next = [...history]
|
|
64
|
-
if (next.length >= max) next.shift()
|
|
65
|
-
next.push(value)
|
|
66
|
-
return next
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
function severityColor(pct: number): string {
|
|
70
|
-
if (pct >= 80) return "$error"
|
|
71
|
-
if (pct >= 60) return "$warning"
|
|
72
|
-
return "$success"
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
function heatColor(temp: number): string {
|
|
76
|
-
if (temp >= 75) return "$error"
|
|
77
|
-
if (temp >= 60) return "$warning"
|
|
78
|
-
return "$success"
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// ============================================================================
|
|
82
|
-
// State
|
|
83
|
-
// ============================================================================
|
|
84
|
-
|
|
85
|
-
interface CoreRow {
|
|
86
|
-
label: string
|
|
87
|
-
pct: number
|
|
88
|
-
freq: string
|
|
89
|
-
temp: number
|
|
90
|
-
mode: string
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
interface MemoryMetrics {
|
|
94
|
-
ramUsed: number
|
|
95
|
-
ramTotal: number
|
|
96
|
-
cached: number
|
|
97
|
-
free: number
|
|
98
|
-
slab: number
|
|
99
|
-
apps: number
|
|
100
|
-
wired: number
|
|
101
|
-
buffers: number
|
|
102
|
-
dirty: number
|
|
103
|
-
shared: number
|
|
104
|
-
reclaim: number
|
|
105
|
-
swapUsed: number
|
|
106
|
-
swapTotal: number
|
|
107
|
-
history: number[]
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
interface NetworkMetrics {
|
|
111
|
-
dlRate: number
|
|
112
|
-
dlPeak: number
|
|
113
|
-
ulRate: number
|
|
114
|
-
ulPeak: number
|
|
115
|
-
connEst: number
|
|
116
|
-
listen: number
|
|
117
|
-
syn: number
|
|
118
|
-
drops: number
|
|
119
|
-
rxPps: string
|
|
120
|
-
txPps: string
|
|
121
|
-
retrans: string
|
|
122
|
-
rtt: string
|
|
123
|
-
dlHistory: number[]
|
|
124
|
-
ulHistory: number[]
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
interface ProcessInfo {
|
|
128
|
-
pid: number
|
|
129
|
-
name: string
|
|
130
|
-
cpu: number
|
|
131
|
-
memp: number
|
|
132
|
-
mem: string
|
|
133
|
-
status: "Running" | "Sleep" | "I/O wait"
|
|
134
|
-
time: string
|
|
135
|
-
io: string
|
|
136
|
-
thr: number
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
interface DashboardState {
|
|
140
|
-
cores: CoreRow[]
|
|
141
|
-
totalCpu: number
|
|
142
|
-
userCpu: number
|
|
143
|
-
sysCpu: number
|
|
144
|
-
waitCpu: number
|
|
145
|
-
load: [number, number, number]
|
|
146
|
-
avgTemp: number
|
|
147
|
-
tasks: number
|
|
148
|
-
avgFreq: string
|
|
149
|
-
ctxPerSec: string
|
|
150
|
-
uptime: string
|
|
151
|
-
pkgPct: number
|
|
152
|
-
power: number
|
|
153
|
-
fan: number
|
|
154
|
-
boostOn: boolean
|
|
155
|
-
cpuHistory: number[]
|
|
156
|
-
memory: MemoryMetrics
|
|
157
|
-
network: NetworkMetrics
|
|
158
|
-
processes: ProcessInfo[]
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
function createInitialState(): DashboardState {
|
|
162
|
-
const cores: CoreRow[] = [
|
|
163
|
-
{ label: "cpu00", pct: 12, freq: "3.62", temp: 39, mode: "idle" },
|
|
164
|
-
{ label: "cpu01", pct: 28, freq: "3.79", temp: 42, mode: "balanced" },
|
|
165
|
-
{ label: "cpu02", pct: 44, freq: "4.02", temp: 47, mode: "steady" },
|
|
166
|
-
{ label: "cpu03", pct: 57, freq: "4.18", temp: 53, mode: "steady" },
|
|
167
|
-
{ label: "cpu04", pct: 63, freq: "4.31", temp: 61, mode: "warm" },
|
|
168
|
-
{ label: "cpu05", pct: 71, freq: "4.47", temp: 68, mode: "boost" },
|
|
169
|
-
{ label: "cpu06", pct: 79, freq: "4.62", temp: 72, mode: "boost" },
|
|
170
|
-
{ label: "cpu07", pct: 83, freq: "4.84", temp: 75, mode: "boost" },
|
|
171
|
-
{ label: "cpu08", pct: 88, freq: "5.02", temp: 77, mode: "turbo" },
|
|
172
|
-
{ label: "cpu09", pct: 94, freq: "5.21", temp: 81, mode: "turbo" },
|
|
173
|
-
]
|
|
174
|
-
|
|
175
|
-
const cpuHistory = [
|
|
176
|
-
1, 2, 2, 3, 2, 4, 5, 4, 6, 5, 4, 6, 7, 6, 5, 6, 7, 6, 5, 4, 5, 6, 5, 7, 6, 5, 6, 7, 7, 6, 5, 4, 5, 6, 5, 4,
|
|
177
|
-
]
|
|
178
|
-
|
|
179
|
-
const memHistory = [4, 4, 5, 5, 4, 5, 6, 5, 5, 6, 6, 5, 6, 6, 7, 6, 6, 5, 6, 6, 5, 5, 6, 5]
|
|
180
|
-
|
|
181
|
-
const memory: MemoryMetrics = {
|
|
182
|
-
ramUsed: 23.7,
|
|
183
|
-
ramTotal: 32.0,
|
|
184
|
-
cached: 5.9,
|
|
185
|
-
free: 2.4,
|
|
186
|
-
slab: 1.1,
|
|
187
|
-
apps: 17.4,
|
|
188
|
-
wired: 1.8,
|
|
189
|
-
buffers: 0.612,
|
|
190
|
-
dirty: 0.212,
|
|
191
|
-
shared: 1.3,
|
|
192
|
-
reclaim: 0.8,
|
|
193
|
-
swapUsed: 2.1,
|
|
194
|
-
swapTotal: 8.0,
|
|
195
|
-
history: memHistory,
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
const dlHistory = [1, 2, 3, 5, 4, 6, 5, 7, 6, 4, 3, 5, 6, 7, 5, 4, 6, 7, 6, 5, 4, 6, 5, 4]
|
|
199
|
-
const ulHistory = [0, 1, 1, 2, 2, 3, 2, 4, 3, 2, 1, 2, 3, 4, 3, 2, 1, 2, 3, 2, 2, 3, 2, 1]
|
|
200
|
-
|
|
201
|
-
const network: NetworkMetrics = {
|
|
202
|
-
dlRate: 428,
|
|
203
|
-
dlPeak: 612,
|
|
204
|
-
ulRate: 86,
|
|
205
|
-
ulPeak: 143,
|
|
206
|
-
connEst: 184,
|
|
207
|
-
listen: 23,
|
|
208
|
-
syn: 2,
|
|
209
|
-
drops: 0,
|
|
210
|
-
rxPps: "61.2kpps",
|
|
211
|
-
txPps: "19.4kpps",
|
|
212
|
-
retrans: "0.08%",
|
|
213
|
-
rtt: "18ms",
|
|
214
|
-
dlHistory,
|
|
215
|
-
ulHistory,
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
const processes: ProcessInfo[] = [
|
|
219
|
-
{
|
|
220
|
-
pid: 31842,
|
|
221
|
-
name: "bun dev --hot src/server.ts",
|
|
222
|
-
cpu: 94.2,
|
|
223
|
-
memp: 3.8,
|
|
224
|
-
mem: "1.22G",
|
|
225
|
-
status: "Running",
|
|
226
|
-
time: "01:42:17",
|
|
227
|
-
io: "24M/s",
|
|
228
|
-
thr: 18,
|
|
229
|
-
},
|
|
230
|
-
{
|
|
231
|
-
pid: 27114,
|
|
232
|
-
name: "node /usr/bin/vite --host",
|
|
233
|
-
cpu: 71.4,
|
|
234
|
-
memp: 2.2,
|
|
235
|
-
mem: "716M",
|
|
236
|
-
status: "Running",
|
|
237
|
-
time: "00:18:09",
|
|
238
|
-
io: "12M/s",
|
|
239
|
-
thr: 26,
|
|
240
|
-
},
|
|
241
|
-
{
|
|
242
|
-
pid: 918,
|
|
243
|
-
name: "postgres: checkpointer",
|
|
244
|
-
cpu: 12.8,
|
|
245
|
-
memp: 1.4,
|
|
246
|
-
mem: "448M",
|
|
247
|
-
status: "Sleep",
|
|
248
|
-
time: "19:22:41",
|
|
249
|
-
io: "3.1M/s",
|
|
250
|
-
thr: 27,
|
|
251
|
-
},
|
|
252
|
-
{
|
|
253
|
-
pid: 1023,
|
|
254
|
-
name: "Code Helper (Renderer)",
|
|
255
|
-
cpu: 9.6,
|
|
256
|
-
memp: 4.8,
|
|
257
|
-
mem: "1.53G",
|
|
258
|
-
status: "Sleep",
|
|
259
|
-
time: "07:13:51",
|
|
260
|
-
io: "1.2M/s",
|
|
261
|
-
thr: 44,
|
|
262
|
-
},
|
|
263
|
-
{
|
|
264
|
-
pid: 2241,
|
|
265
|
-
name: "docker-desktop",
|
|
266
|
-
cpu: 8.9,
|
|
267
|
-
memp: 6.3,
|
|
268
|
-
mem: "2.01G",
|
|
269
|
-
status: "Running",
|
|
270
|
-
time: "11:08:04",
|
|
271
|
-
io: "9.4M/s",
|
|
272
|
-
thr: 61,
|
|
273
|
-
},
|
|
274
|
-
{
|
|
275
|
-
pid: 1542,
|
|
276
|
-
name: "redis-server *:6379",
|
|
277
|
-
cpu: 6.7,
|
|
278
|
-
memp: 0.9,
|
|
279
|
-
mem: "289M",
|
|
280
|
-
status: "Sleep",
|
|
281
|
-
time: "02:51:17",
|
|
282
|
-
io: "642K/s",
|
|
283
|
-
thr: 8,
|
|
284
|
-
},
|
|
285
|
-
{
|
|
286
|
-
pid: 612,
|
|
287
|
-
name: "tailscaled --tun=userspace-networking",
|
|
288
|
-
cpu: 5.4,
|
|
289
|
-
memp: 0.4,
|
|
290
|
-
mem: "132M",
|
|
291
|
-
status: "Sleep",
|
|
292
|
-
time: "05:44:22",
|
|
293
|
-
io: "218K/s",
|
|
294
|
-
thr: 19,
|
|
295
|
-
},
|
|
296
|
-
{
|
|
297
|
-
pid: 33210,
|
|
298
|
-
name: "bun test --watch",
|
|
299
|
-
cpu: 4.2,
|
|
300
|
-
memp: 1.1,
|
|
301
|
-
mem: "356M",
|
|
302
|
-
status: "Running",
|
|
303
|
-
time: "00:06:38",
|
|
304
|
-
io: "4.6M/s",
|
|
305
|
-
thr: 12,
|
|
306
|
-
},
|
|
307
|
-
{
|
|
308
|
-
pid: 1804,
|
|
309
|
-
name: "nginx: worker process",
|
|
310
|
-
cpu: 3.7,
|
|
311
|
-
memp: 0.2,
|
|
312
|
-
mem: "72M",
|
|
313
|
-
status: "Sleep",
|
|
314
|
-
time: "03:17:09",
|
|
315
|
-
io: "118K/s",
|
|
316
|
-
thr: 5,
|
|
317
|
-
},
|
|
318
|
-
{
|
|
319
|
-
pid: 2877,
|
|
320
|
-
name: "Chrome Helper (GPU)",
|
|
321
|
-
cpu: 3.2,
|
|
322
|
-
memp: 2.7,
|
|
323
|
-
mem: "864M",
|
|
324
|
-
status: "Sleep",
|
|
325
|
-
time: "06:29:33",
|
|
326
|
-
io: "2.3M/s",
|
|
327
|
-
thr: 23,
|
|
328
|
-
},
|
|
329
|
-
{
|
|
330
|
-
pid: 451,
|
|
331
|
-
name: "kernel_task",
|
|
332
|
-
cpu: 2.8,
|
|
333
|
-
memp: 0.1,
|
|
334
|
-
mem: "42M",
|
|
335
|
-
status: "Running",
|
|
336
|
-
time: "22:54:48",
|
|
337
|
-
io: "0",
|
|
338
|
-
thr: 179,
|
|
339
|
-
},
|
|
340
|
-
{
|
|
341
|
-
pid: 1942,
|
|
342
|
-
name: "syncthing serve --no-browser",
|
|
343
|
-
cpu: 2.1,
|
|
344
|
-
memp: 0.8,
|
|
345
|
-
mem: "258M",
|
|
346
|
-
status: "Sleep",
|
|
347
|
-
time: "14:05:14",
|
|
348
|
-
io: "884K/s",
|
|
349
|
-
thr: 16,
|
|
350
|
-
},
|
|
351
|
-
{
|
|
352
|
-
pid: 7621,
|
|
353
|
-
name: "python scripts/indexer.py --incremental",
|
|
354
|
-
cpu: 1.9,
|
|
355
|
-
memp: 1.9,
|
|
356
|
-
mem: "604M",
|
|
357
|
-
status: "I/O wait",
|
|
358
|
-
time: "00:43:58",
|
|
359
|
-
io: "14M/s",
|
|
360
|
-
thr: 9,
|
|
361
|
-
},
|
|
362
|
-
{
|
|
363
|
-
pid: 266,
|
|
364
|
-
name: "systemd-journald",
|
|
365
|
-
cpu: 1.2,
|
|
366
|
-
memp: 0.1,
|
|
367
|
-
mem: "38M",
|
|
368
|
-
status: "Sleep",
|
|
369
|
-
time: "09:12:44",
|
|
370
|
-
io: "96K/s",
|
|
371
|
-
thr: 3,
|
|
372
|
-
},
|
|
373
|
-
{
|
|
374
|
-
pid: 74,
|
|
375
|
-
name: "zsh - bun gen-mockup.ts",
|
|
376
|
-
cpu: 0.2,
|
|
377
|
-
memp: 0.0,
|
|
378
|
-
mem: "6M",
|
|
379
|
-
status: "Running",
|
|
380
|
-
time: "00:00:03",
|
|
381
|
-
io: "0",
|
|
382
|
-
thr: 1,
|
|
383
|
-
},
|
|
384
|
-
]
|
|
385
|
-
|
|
386
|
-
return {
|
|
387
|
-
cores,
|
|
388
|
-
totalCpu: 67,
|
|
389
|
-
userCpu: 38,
|
|
390
|
-
sysCpu: 12,
|
|
391
|
-
waitCpu: 14,
|
|
392
|
-
load: [4.21, 3.88, 3.11],
|
|
393
|
-
avgTemp: 71,
|
|
394
|
-
tasks: 287,
|
|
395
|
-
avgFreq: "4.31",
|
|
396
|
-
ctxPerSec: "128k",
|
|
397
|
-
uptime: "12d 06h",
|
|
398
|
-
pkgPct: 67,
|
|
399
|
-
power: 84,
|
|
400
|
-
fan: 1460,
|
|
401
|
-
boostOn: true,
|
|
402
|
-
cpuHistory,
|
|
403
|
-
memory,
|
|
404
|
-
network,
|
|
405
|
-
processes,
|
|
406
|
-
}
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
function tickState(prev: DashboardState): DashboardState {
|
|
410
|
-
const cores = prev.cores.map((core) => {
|
|
411
|
-
const pct = Math.max(0, Math.min(100, Math.round(jitter(core.pct, 10))))
|
|
412
|
-
return { ...core, pct }
|
|
413
|
-
})
|
|
414
|
-
|
|
415
|
-
const totalCpu = Math.round(jitter(prev.totalCpu, 8))
|
|
416
|
-
const cpuHistory = pushHistory(prev.cpuHistory, Math.max(0, Math.min(7, Math.round(totalCpu / 14))), 36)
|
|
417
|
-
|
|
418
|
-
const ramPct = Math.round((prev.memory.ramUsed / prev.memory.ramTotal) * 100)
|
|
419
|
-
const memHistory = pushHistory(prev.memory.history, Math.max(0, Math.min(7, Math.round(ramPct / 14))), 24)
|
|
420
|
-
const memory: MemoryMetrics = { ...prev.memory, history: memHistory }
|
|
421
|
-
|
|
422
|
-
const dlVal = Math.max(0, Math.min(7, Math.round(jitter(5, 4))))
|
|
423
|
-
const ulVal = Math.max(0, Math.min(7, Math.round(jitter(2, 3))))
|
|
424
|
-
const dlHistory = pushHistory(prev.network.dlHistory, dlVal, 24)
|
|
425
|
-
const ulHistory = pushHistory(prev.network.ulHistory, ulVal, 24)
|
|
426
|
-
const network: NetworkMetrics = { ...prev.network, dlHistory, ulHistory }
|
|
427
|
-
|
|
428
|
-
const processes = prev.processes.map((p) => ({
|
|
429
|
-
...p,
|
|
430
|
-
cpu: Math.max(0, Number(jitter(p.cpu, 4).toFixed(1))),
|
|
431
|
-
}))
|
|
432
|
-
|
|
433
|
-
return { ...prev, cores, totalCpu, cpuHistory, memory, network, processes }
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
// ============================================================================
|
|
437
|
-
// Shared Components
|
|
438
|
-
// ============================================================================
|
|
439
|
-
|
|
440
|
-
function Sep() {
|
|
441
|
-
return <Muted>{"┄".repeat(50)}</Muted>
|
|
442
|
-
}
|
|
443
|
-
|
|
444
|
-
function LR({ children }: { children: React.ReactNode }) {
|
|
445
|
-
return (
|
|
446
|
-
<Box justifyContent="space-between" wrap="truncate">
|
|
447
|
-
{children}
|
|
448
|
-
</Box>
|
|
449
|
-
)
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
/** Label-value pair: `Label value` with muted label */
|
|
453
|
-
function LV({ label, value, color }: { label: string; value: string | number; color?: string }) {
|
|
454
|
-
return (
|
|
455
|
-
<Box gap={1}>
|
|
456
|
-
<Muted>{label}</Muted>
|
|
457
|
-
<Text color={color}>{`${value}`}</Text>
|
|
458
|
-
</Box>
|
|
459
|
-
)
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
// ============================================================================
|
|
463
|
-
// CPU Panel
|
|
464
|
-
// ============================================================================
|
|
465
|
-
|
|
466
|
-
function CpuSummary({ state }: { state: DashboardState }) {
|
|
467
|
-
return (
|
|
468
|
-
<>
|
|
469
|
-
<LR>
|
|
470
|
-
<Box gap={1} wrap="truncate">
|
|
471
|
-
<Muted>Total</Muted>
|
|
472
|
-
<Text color={severityColor(state.totalCpu)}>{`${state.totalCpu}%`}</Text>
|
|
473
|
-
<Text color={severityColor(state.totalCpu)}>{miniBar(state.totalCpu, 24)}</Text>
|
|
474
|
-
</Box>
|
|
475
|
-
<Box gap={2} wrap="truncate">
|
|
476
|
-
<LV
|
|
477
|
-
label="Load"
|
|
478
|
-
value={`${state.load[0].toFixed(2)} ${state.load[1].toFixed(2)} ${state.load[2].toFixed(2)}`}
|
|
479
|
-
/>
|
|
480
|
-
<LV label="Temp" value={`${state.avgTemp}\u00B0C`} color={heatColor(state.avgTemp)} />
|
|
481
|
-
<LV label="Tasks" value={state.tasks} />
|
|
482
|
-
</Box>
|
|
483
|
-
</LR>
|
|
484
|
-
<LR>
|
|
485
|
-
<Box gap={2} wrap="truncate">
|
|
486
|
-
<LV label="User" value={`${state.userCpu}%`} color={severityColor(state.userCpu)} />
|
|
487
|
-
<LV label="Sys" value={`${state.sysCpu}%`} color={severityColor(state.sysCpu)} />
|
|
488
|
-
<LV label="Wait" value={`${state.waitCpu}%`} color={severityColor(state.waitCpu)} />
|
|
489
|
-
</Box>
|
|
490
|
-
<Box gap={2} wrap="truncate">
|
|
491
|
-
<LV label="Avg" value={`${state.avgFreq}GHz`} />
|
|
492
|
-
<LV label="Ctx/s" value={state.ctxPerSec} />
|
|
493
|
-
<LV label="Uptime" value={state.uptime} />
|
|
494
|
-
</Box>
|
|
495
|
-
</LR>
|
|
496
|
-
</>
|
|
497
|
-
)
|
|
498
|
-
}
|
|
499
|
-
|
|
500
|
-
function CpuCore({ core }: { core: CoreRow }) {
|
|
501
|
-
return (
|
|
502
|
-
<LR>
|
|
503
|
-
<Box gap={1} wrap="truncate">
|
|
504
|
-
<Muted>{core.label}</Muted>
|
|
505
|
-
<Text color={severityColor(core.pct)}>{`${core.pct}%`.padStart(4)}</Text>
|
|
506
|
-
<Text color={severityColor(core.pct)}>{miniBar(core.pct, 24)}</Text>
|
|
507
|
-
<Muted>{`${core.freq}GHz`}</Muted>
|
|
508
|
-
</Box>
|
|
509
|
-
<Box gap={2} wrap="truncate">
|
|
510
|
-
<Box gap={1}>
|
|
511
|
-
<Muted>temp</Muted>
|
|
512
|
-
<Text color={heatColor(core.temp)}>{`${core.temp}\u00B0C`}</Text>
|
|
513
|
-
</Box>
|
|
514
|
-
<Text color={severityColor(core.pct)}>{core.mode}</Text>
|
|
515
|
-
</Box>
|
|
516
|
-
</LR>
|
|
517
|
-
)
|
|
518
|
-
}
|
|
519
|
-
|
|
520
|
-
function CpuFooter({ state }: { state: DashboardState }) {
|
|
521
|
-
return (
|
|
522
|
-
<>
|
|
523
|
-
<LR>
|
|
524
|
-
<Box gap={1} wrap="truncate">
|
|
525
|
-
<Muted>Pkg</Muted>
|
|
526
|
-
<Text color={severityColor(state.pkgPct)}>{`${state.pkgPct}%`}</Text>
|
|
527
|
-
<Text color={severityColor(state.pkgPct)}>{miniBar(state.pkgPct, 24)}</Text>
|
|
528
|
-
</Box>
|
|
529
|
-
<Box gap={2} wrap="truncate">
|
|
530
|
-
<LV label="Power" value={`${state.power}W`} />
|
|
531
|
-
<LV label="Fan" value={`${state.fan}RPM`} />
|
|
532
|
-
<LV label="Boost" value="on" color="$success" />
|
|
533
|
-
</Box>
|
|
534
|
-
</LR>
|
|
535
|
-
<LR>
|
|
536
|
-
<Box gap={1} wrap="truncate">
|
|
537
|
-
<Muted>History</Muted>
|
|
538
|
-
<Text color="$primary">{sparkline(state.cpuHistory)}</Text>
|
|
539
|
-
</Box>
|
|
540
|
-
<Muted>60s</Muted>
|
|
541
|
-
</LR>
|
|
542
|
-
</>
|
|
543
|
-
)
|
|
544
|
-
}
|
|
545
|
-
|
|
546
|
-
function CpuPanel({ state }: { state: DashboardState }) {
|
|
547
|
-
return (
|
|
548
|
-
<Box flexDirection="column" flexGrow={1}>
|
|
549
|
-
<CpuSummary state={state} />
|
|
550
|
-
<Sep />
|
|
551
|
-
{state.cores.map((core) => (
|
|
552
|
-
<CpuCore key={core.label} core={core} />
|
|
553
|
-
))}
|
|
554
|
-
<Sep />
|
|
555
|
-
<CpuFooter state={state} />
|
|
556
|
-
</Box>
|
|
557
|
-
)
|
|
558
|
-
}
|
|
559
|
-
|
|
560
|
-
// ============================================================================
|
|
561
|
-
// Memory Panel
|
|
562
|
-
// ============================================================================
|
|
563
|
-
|
|
564
|
-
function MemoryPanel({ memory }: { memory: MemoryMetrics }) {
|
|
565
|
-
const ramPct = Math.round((memory.ramUsed / memory.ramTotal) * 100)
|
|
566
|
-
const swapPct = Math.round((memory.swapUsed / memory.swapTotal) * 100)
|
|
567
|
-
const avail = (memory.ramTotal - memory.ramUsed).toFixed(1)
|
|
568
|
-
|
|
569
|
-
return (
|
|
570
|
-
<Box flexDirection="column" flexGrow={1}>
|
|
571
|
-
<LR>
|
|
572
|
-
<Box wrap="truncate">
|
|
573
|
-
<Muted>{"RAM "}</Muted>
|
|
574
|
-
<Text>{`${memory.ramUsed.toFixed(1)} / ${memory.ramTotal.toFixed(1)} GiB `}</Text>
|
|
575
|
-
<Text color={severityColor(ramPct)}>{`${ramPct}% `}</Text>
|
|
576
|
-
<Text color={severityColor(ramPct)}>{miniBar(ramPct, 12)}</Text>
|
|
577
|
-
</Box>
|
|
578
|
-
<Box gap={1} wrap="truncate">
|
|
579
|
-
<Muted>avail</Muted>
|
|
580
|
-
<Text>{`${avail}G`}</Text>
|
|
581
|
-
</Box>
|
|
582
|
-
</LR>
|
|
583
|
-
<LR>
|
|
584
|
-
<Box gap={2} wrap="truncate">
|
|
585
|
-
<LV label="Used" value={`${memory.ramUsed.toFixed(1)}G`} />
|
|
586
|
-
<LV label="Cache" value={`${memory.cached.toFixed(1)}G`} />
|
|
587
|
-
</Box>
|
|
588
|
-
<Box gap={2} wrap="truncate">
|
|
589
|
-
<LV label="Free" value={`${memory.free.toFixed(1)}G`} />
|
|
590
|
-
<LV label="Slab" value={`${memory.slab.toFixed(1)}G`} />
|
|
591
|
-
</Box>
|
|
592
|
-
</LR>
|
|
593
|
-
<LR>
|
|
594
|
-
<Box wrap="truncate">
|
|
595
|
-
<Muted>{"Swap "}</Muted>
|
|
596
|
-
<Text>{`${memory.swapUsed.toFixed(1)} / ${memory.swapTotal.toFixed(1)} GiB `}</Text>
|
|
597
|
-
<Text color={severityColor(swapPct)}>{`${swapPct}% `}</Text>
|
|
598
|
-
<Text color={severityColor(swapPct)}>{miniBar(swapPct, 12)}</Text>
|
|
599
|
-
</Box>
|
|
600
|
-
<Box gap={1} wrap="truncate">
|
|
601
|
-
<Muted>zram</Muted>
|
|
602
|
-
<Text>off</Text>
|
|
603
|
-
</Box>
|
|
604
|
-
</LR>
|
|
605
|
-
<Sep />
|
|
606
|
-
<LR>
|
|
607
|
-
<Box gap={2} wrap="truncate">
|
|
608
|
-
<LV label="Apps" value={`${memory.apps.toFixed(1)}G`} />
|
|
609
|
-
<LV label="Wired" value={`${memory.wired.toFixed(1)}G`} />
|
|
610
|
-
</Box>
|
|
611
|
-
<LV label="Buffers" value="612M" />
|
|
612
|
-
</LR>
|
|
613
|
-
<LR>
|
|
614
|
-
<Box gap={2} wrap="truncate">
|
|
615
|
-
<LV label="Dirty" value="212M" />
|
|
616
|
-
<LV label="Shared" value={`${memory.shared.toFixed(1)}G`} />
|
|
617
|
-
</Box>
|
|
618
|
-
<LV label="Reclaim" value={`${memory.reclaim.toFixed(1)}G`} />
|
|
619
|
-
</LR>
|
|
620
|
-
<LR>
|
|
621
|
-
<Box gap={1} wrap="truncate">
|
|
622
|
-
<Muted>Trend</Muted>
|
|
623
|
-
<Text color="$primary">{sparkline(memory.history)}</Text>
|
|
624
|
-
</Box>
|
|
625
|
-
<Muted>30m</Muted>
|
|
626
|
-
</LR>
|
|
627
|
-
</Box>
|
|
628
|
-
)
|
|
629
|
-
}
|
|
630
|
-
|
|
631
|
-
// ============================================================================
|
|
632
|
-
// Network Panel
|
|
633
|
-
// ============================================================================
|
|
634
|
-
|
|
635
|
-
function NetworkPanel({ network }: { network: NetworkMetrics }) {
|
|
636
|
-
const dlPct = Math.round((network.dlRate / 630) * 100)
|
|
637
|
-
const ulPct = Math.round((network.ulRate / 400) * 100)
|
|
638
|
-
|
|
639
|
-
return (
|
|
640
|
-
<Box flexDirection="column" flexGrow={1}>
|
|
641
|
-
<LR>
|
|
642
|
-
<Box wrap="truncate">
|
|
643
|
-
<Muted>{"DL "}</Muted>
|
|
644
|
-
<Text>{`${network.dlRate} Mb/s `}</Text>
|
|
645
|
-
<Text color={severityColor(dlPct)}>{`${dlPct}% `}</Text>
|
|
646
|
-
<Text color={severityColor(dlPct)}>{miniBar(dlPct, 12)}</Text>
|
|
647
|
-
</Box>
|
|
648
|
-
<Box gap={1} wrap="truncate">
|
|
649
|
-
<Muted>peak</Muted>
|
|
650
|
-
<Text>{`${network.dlPeak}`}</Text>
|
|
651
|
-
</Box>
|
|
652
|
-
</LR>
|
|
653
|
-
<LR>
|
|
654
|
-
<Box wrap="truncate">
|
|
655
|
-
<Muted>{"UL "}</Muted>
|
|
656
|
-
<Text color="$info">{`${network.ulRate} Mb/s `}</Text>
|
|
657
|
-
<Text color="$info">{`${ulPct}% `}</Text>
|
|
658
|
-
<Text color="$info">{miniBar(ulPct, 12)}</Text>
|
|
659
|
-
</Box>
|
|
660
|
-
<Box gap={1} wrap="truncate">
|
|
661
|
-
<Muted>peak</Muted>
|
|
662
|
-
<Text>{`${network.ulPeak}`}</Text>
|
|
663
|
-
</Box>
|
|
664
|
-
</LR>
|
|
665
|
-
<Sep />
|
|
666
|
-
<LR>
|
|
667
|
-
<Box gap={2} wrap="truncate">
|
|
668
|
-
<LV label="Conn" value={`${network.connEst} est`} />
|
|
669
|
-
<LV label="Listen" value={network.listen} />
|
|
670
|
-
</Box>
|
|
671
|
-
<Box gap={2} wrap="truncate">
|
|
672
|
-
<LV label="SYN" value={network.syn} />
|
|
673
|
-
<LV label="Drops" value={network.drops} />
|
|
674
|
-
</Box>
|
|
675
|
-
</LR>
|
|
676
|
-
<LR>
|
|
677
|
-
<Box gap={2} wrap="truncate">
|
|
678
|
-
<LV label="Rx" value={network.rxPps} />
|
|
679
|
-
<LV label="Tx" value={network.txPps} />
|
|
680
|
-
</Box>
|
|
681
|
-
<Box gap={2} wrap="truncate">
|
|
682
|
-
<LV label="Retrans" value={network.retrans} />
|
|
683
|
-
<LV label="RTT" value={network.rtt} />
|
|
684
|
-
</Box>
|
|
685
|
-
</LR>
|
|
686
|
-
<LR>
|
|
687
|
-
<Box gap={1} wrap="truncate">
|
|
688
|
-
<Muted>DL</Muted>
|
|
689
|
-
<Text color="$primary">{sparkline(network.dlHistory)}</Text>
|
|
690
|
-
</Box>
|
|
691
|
-
<Muted>60s</Muted>
|
|
692
|
-
</LR>
|
|
693
|
-
<LR>
|
|
694
|
-
<Box gap={1} wrap="truncate">
|
|
695
|
-
<Muted>UL</Muted>
|
|
696
|
-
<Text color="$info">{sparkline(network.ulHistory)}</Text>
|
|
697
|
-
</Box>
|
|
698
|
-
<Muted>60s</Muted>
|
|
699
|
-
</LR>
|
|
700
|
-
</Box>
|
|
701
|
-
)
|
|
702
|
-
}
|
|
703
|
-
|
|
704
|
-
// ============================================================================
|
|
705
|
-
// Process Table
|
|
706
|
-
// ============================================================================
|
|
707
|
-
|
|
708
|
-
const COL = { pid: 6, name: 62, cpu: 6, memp: 6, mem: 9, status: 10, time: 10, io: 11, thr: 5 }
|
|
709
|
-
|
|
710
|
-
function statusColor(status: ProcessInfo["status"]): string | undefined {
|
|
711
|
-
switch (status) {
|
|
712
|
-
case "Running":
|
|
713
|
-
return "$success"
|
|
714
|
-
case "I/O wait":
|
|
715
|
-
return "$warning"
|
|
716
|
-
case "Sleep":
|
|
717
|
-
default:
|
|
718
|
-
return "$muted"
|
|
719
|
-
}
|
|
720
|
-
}
|
|
721
|
-
|
|
722
|
-
function ProcessHeader() {
|
|
723
|
-
return (
|
|
724
|
-
<Box wrap="clip">
|
|
725
|
-
<Muted>{`${"PID".padStart(COL.pid)} `}</Muted>
|
|
726
|
-
<Muted>{`${"NAME".padEnd(COL.name)} `}</Muted>
|
|
727
|
-
<Text bold color="$primary">{`${"CPU%\u2193".padStart(COL.cpu)} `}</Text>
|
|
728
|
-
<Muted>{`${"MEM%".padStart(COL.memp)} `}</Muted>
|
|
729
|
-
<Muted>{`${"MEM".padStart(COL.mem)} `}</Muted>
|
|
730
|
-
<Muted>{`${"STATUS".padEnd(COL.status)} `}</Muted>
|
|
731
|
-
<Muted>{`${"TIME".padStart(COL.time)} `}</Muted>
|
|
732
|
-
<Muted>{`${"IO".padStart(COL.io)} `}</Muted>
|
|
733
|
-
<Muted>{`${"THR".padStart(COL.thr)}`}</Muted>
|
|
734
|
-
</Box>
|
|
735
|
-
)
|
|
736
|
-
}
|
|
737
|
-
|
|
738
|
-
function ProcessRow({ proc, isTop }: { proc: ProcessInfo; isTop: boolean }) {
|
|
739
|
-
const cpuColor = severityColor(proc.cpu)
|
|
740
|
-
const ioColor = proc.io === "0" ? "$muted" : "$primary"
|
|
741
|
-
|
|
742
|
-
return (
|
|
743
|
-
<Box wrap="clip">
|
|
744
|
-
<Text>{`${String(proc.pid).padStart(COL.pid)} `}</Text>
|
|
745
|
-
<Text bold={isTop}>{`${proc.name.padEnd(COL.name).slice(0, COL.name)} `}</Text>
|
|
746
|
-
<Text bold={isTop} color={cpuColor}>{`${proc.cpu.toFixed(1).padStart(5)}% `}</Text>
|
|
747
|
-
<Text color={severityColor(proc.memp * 10)}>{`${proc.memp.toFixed(1).padStart(5)}% `}</Text>
|
|
748
|
-
<Text>{`${proc.mem.padStart(COL.mem)} `}</Text>
|
|
749
|
-
<Text color={statusColor(proc.status)}>{`${proc.status.padEnd(COL.status)} `}</Text>
|
|
750
|
-
<Text>{`${proc.time.padStart(COL.time)} `}</Text>
|
|
751
|
-
<Text color={ioColor}>{`${proc.io.padStart(COL.io)} `}</Text>
|
|
752
|
-
<Text>{`${String(proc.thr).padStart(COL.thr)}`}</Text>
|
|
753
|
-
</Box>
|
|
754
|
-
)
|
|
755
|
-
}
|
|
756
|
-
|
|
757
|
-
function ProcessFooter({ processes, state }: { processes: ProcessInfo[]; state: DashboardState }) {
|
|
758
|
-
const running = processes.filter((p) => p.status === "Running").length
|
|
759
|
-
const iowait = processes.filter((p) => p.status === "I/O wait").length
|
|
760
|
-
const sleeping = 184 - running - iowait
|
|
761
|
-
const ramPct = Math.round((state.memory.ramUsed / state.memory.ramTotal) * 100)
|
|
762
|
-
|
|
763
|
-
return (
|
|
764
|
-
<LR>
|
|
765
|
-
<Box gap={2} wrap="truncate">
|
|
766
|
-
<Muted>184 processes</Muted>
|
|
767
|
-
<Text color="$success">{`${running} running`}</Text>
|
|
768
|
-
<Muted>{`${sleeping} sleeping`}</Muted>
|
|
769
|
-
<Text color="$warning">{`${iowait} iowait`}</Text>
|
|
770
|
-
</Box>
|
|
771
|
-
<Box gap={2} wrap="truncate">
|
|
772
|
-
<LV label="Threads" value="1,942" />
|
|
773
|
-
<LV label="CPU" value={`${state.totalCpu}%`} color={severityColor(state.totalCpu)} />
|
|
774
|
-
<LV label="MEM" value={`${ramPct}%`} color={severityColor(ramPct)} />
|
|
775
|
-
<Text color="$primary">{`428\u2193`}</Text>
|
|
776
|
-
<Text color="$info">{`86\u2191`}</Text>
|
|
777
|
-
</Box>
|
|
778
|
-
</LR>
|
|
779
|
-
)
|
|
780
|
-
}
|
|
781
|
-
|
|
782
|
-
function ProcessPanel({ state }: { state: DashboardState }) {
|
|
783
|
-
const sorted = [...state.processes].sort((a, b) => b.cpu - a.cpu)
|
|
784
|
-
|
|
785
|
-
return (
|
|
786
|
-
<Box flexDirection="column" flexGrow={1}>
|
|
787
|
-
<ProcessHeader />
|
|
788
|
-
<Sep />
|
|
789
|
-
{sorted.map((proc, i) => (
|
|
790
|
-
<ProcessRow key={proc.pid} proc={proc} isTop={i === 0} />
|
|
791
|
-
))}
|
|
792
|
-
<Sep />
|
|
793
|
-
<ProcessFooter processes={state.processes} state={state} />
|
|
794
|
-
</Box>
|
|
795
|
-
)
|
|
796
|
-
}
|
|
797
|
-
|
|
798
|
-
// ============================================================================
|
|
799
|
-
// Layouts
|
|
800
|
-
// ============================================================================
|
|
801
|
-
|
|
802
|
-
/** Panel with titled first row inside standard border */
|
|
803
|
-
function Panel({
|
|
804
|
-
title,
|
|
805
|
-
subtitle,
|
|
806
|
-
children,
|
|
807
|
-
flexGrow,
|
|
808
|
-
flexBasis,
|
|
809
|
-
}: {
|
|
810
|
-
title: string
|
|
811
|
-
subtitle?: string
|
|
812
|
-
children: React.ReactNode
|
|
813
|
-
flexGrow?: number
|
|
814
|
-
flexBasis?: number
|
|
815
|
-
}) {
|
|
816
|
-
return (
|
|
817
|
-
<Box
|
|
818
|
-
borderStyle="round"
|
|
819
|
-
borderColor="$primary"
|
|
820
|
-
paddingX={1}
|
|
821
|
-
flexDirection="column"
|
|
822
|
-
flexGrow={flexGrow}
|
|
823
|
-
flexBasis={flexBasis}
|
|
824
|
-
>
|
|
825
|
-
<LR>
|
|
826
|
-
<Text bold color="$primary">
|
|
827
|
-
{` ${title} `}
|
|
828
|
-
</Text>
|
|
829
|
-
{subtitle && <Muted>{` ${subtitle} `}</Muted>}
|
|
830
|
-
</LR>
|
|
831
|
-
{children}
|
|
832
|
-
</Box>
|
|
833
|
-
)
|
|
834
|
-
}
|
|
835
|
-
|
|
836
|
-
function WideLayout({ state }: { state: DashboardState }) {
|
|
837
|
-
return (
|
|
838
|
-
<Box flexDirection="column" flexGrow={1}>
|
|
839
|
-
{/* Top row: CPU (left ~60%) | Memory + Network stacked (right ~40%) */}
|
|
840
|
-
<Box flexDirection="row" gap={1}>
|
|
841
|
-
<Panel title="CPU / Compute" subtitle="10 logical" flexGrow={3} flexBasis={0}>
|
|
842
|
-
<CpuPanel state={state} />
|
|
843
|
-
</Panel>
|
|
844
|
-
<Box flexDirection="column" flexGrow={2} flexBasis={0}>
|
|
845
|
-
<Panel title="Memory" subtitle={`${state.memory.ramTotal.toFixed(0)} GiB`}>
|
|
846
|
-
<MemoryPanel memory={state.memory} />
|
|
847
|
-
</Panel>
|
|
848
|
-
<Panel title="Network" subtitle="en0 • wifi6">
|
|
849
|
-
<NetworkPanel network={state.network} />
|
|
850
|
-
</Panel>
|
|
851
|
-
</Box>
|
|
852
|
-
</Box>
|
|
853
|
-
{/* Bottom: Process table (full width) */}
|
|
854
|
-
<Panel title="Processes" subtitle="sorted by CPU%">
|
|
855
|
-
<ProcessPanel state={state} />
|
|
856
|
-
</Panel>
|
|
857
|
-
</Box>
|
|
858
|
-
)
|
|
859
|
-
}
|
|
860
|
-
|
|
861
|
-
function NarrowLayout({ state }: { state: DashboardState }) {
|
|
862
|
-
return (
|
|
863
|
-
<Box flexDirection="column" flexGrow={1}>
|
|
864
|
-
<Tabs defaultValue="cpu">
|
|
865
|
-
<Box justifyContent="space-between" paddingX={1}>
|
|
866
|
-
<TabList>
|
|
867
|
-
<Tab value="cpu">CPU</Tab>
|
|
868
|
-
<Tab value="memory">Memory</Tab>
|
|
869
|
-
<Tab value="network">Network</Tab>
|
|
870
|
-
<Tab value="processes">Processes</Tab>
|
|
871
|
-
</TabList>
|
|
872
|
-
</Box>
|
|
873
|
-
|
|
874
|
-
<TabPanel value="cpu">
|
|
875
|
-
<Panel title="CPU / Compute" subtitle="10 logical">
|
|
876
|
-
<CpuPanel state={state} />
|
|
877
|
-
</Panel>
|
|
878
|
-
</TabPanel>
|
|
879
|
-
<TabPanel value="memory">
|
|
880
|
-
<Panel title="Memory" subtitle={`${state.memory.ramTotal.toFixed(0)} GiB`}>
|
|
881
|
-
<MemoryPanel memory={state.memory} />
|
|
882
|
-
</Panel>
|
|
883
|
-
</TabPanel>
|
|
884
|
-
<TabPanel value="network">
|
|
885
|
-
<Panel title="Network" subtitle="en0 • wifi6">
|
|
886
|
-
<NetworkPanel network={state.network} />
|
|
887
|
-
</Panel>
|
|
888
|
-
</TabPanel>
|
|
889
|
-
<TabPanel value="processes">
|
|
890
|
-
<Panel title="Processes" subtitle="sorted by CPU%">
|
|
891
|
-
<ProcessPanel state={state} />
|
|
892
|
-
</Panel>
|
|
893
|
-
</TabPanel>
|
|
894
|
-
</Tabs>
|
|
895
|
-
</Box>
|
|
896
|
-
)
|
|
897
|
-
}
|
|
898
|
-
|
|
899
|
-
// ============================================================================
|
|
900
|
-
// Dashboard
|
|
901
|
-
// ============================================================================
|
|
902
|
-
|
|
903
|
-
export function Dashboard({ static: isStatic }: { static?: boolean } = {}) {
|
|
904
|
-
const { exit } = useApp()
|
|
905
|
-
const { width } = useBoxRect()
|
|
906
|
-
const [state, setState] = useState(createInitialState)
|
|
907
|
-
// Process table needs ~135 cols; below that switch to tabbed layout
|
|
908
|
-
const isNarrow = width > 0 && width < 130
|
|
909
|
-
|
|
910
|
-
useInterval(() => setState((prev) => tickState(prev)), 500, !isStatic)
|
|
911
|
-
|
|
912
|
-
useInput((input: string, key: Key) => {
|
|
913
|
-
if (input === "q" || key.escape) exit()
|
|
914
|
-
})
|
|
915
|
-
|
|
916
|
-
if (isNarrow) {
|
|
917
|
-
return <NarrowLayout state={state} />
|
|
918
|
-
}
|
|
919
|
-
|
|
920
|
-
return (
|
|
921
|
-
<Box flexDirection="column" flexGrow={1}>
|
|
922
|
-
<Box wrap="truncate">
|
|
923
|
-
<Text bold color="$primary">
|
|
924
|
-
Silvery TUI
|
|
925
|
-
</Text>
|
|
926
|
-
<Muted>{" system monitor showcase "}</Muted>
|
|
927
|
-
<Text color="$primary">devbox-01</Text>
|
|
928
|
-
<Muted>{"┄".repeat(19)}</Muted>
|
|
929
|
-
<Muted>14:27 UTC [h]help [1]cpu [2]mem [3]net [p]proc [/]filter [q]quit</Muted>
|
|
930
|
-
</Box>
|
|
931
|
-
<WideLayout state={state} />
|
|
932
|
-
</Box>
|
|
933
|
-
)
|
|
934
|
-
}
|
|
935
|
-
|
|
936
|
-
// ============================================================================
|
|
937
|
-
// Main
|
|
938
|
-
// ============================================================================
|
|
939
|
-
|
|
940
|
-
export async function main() {
|
|
941
|
-
using term = createTerm()
|
|
942
|
-
const { waitUntilExit } = await render(
|
|
943
|
-
<ExampleBanner meta={meta} controls="h/l tabs Esc/q quit">
|
|
944
|
-
<Dashboard />
|
|
945
|
-
</ExampleBanner>,
|
|
946
|
-
term,
|
|
947
|
-
)
|
|
948
|
-
await waitUntilExit()
|
|
949
|
-
}
|
|
950
|
-
|
|
951
|
-
if (import.meta.main) {
|
|
952
|
-
await main()
|
|
953
|
-
}
|