tuimon 0.1.0 → 0.3.0
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/AI.md +191 -0
- package/README.md +240 -94
- package/dist/browser.d.ts.map +1 -1
- package/dist/browser.js +3 -0
- package/dist/browser.js.map +1 -1
- package/dist/cli.js +224 -3
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +17 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +106 -0
- package/dist/config.js.map +1 -0
- package/dist/fkeybar.d.ts.map +1 -1
- package/dist/fkeybar.js +13 -0
- package/dist/fkeybar.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +148 -18
- package/dist/index.js.map +1 -1
- package/dist/layout/generator-css.d.ts +3 -0
- package/dist/layout/generator-css.d.ts.map +1 -0
- package/dist/layout/generator-css.js +202 -0
- package/dist/layout/generator-css.js.map +1 -0
- package/dist/layout/generator-js.d.ts +3 -0
- package/dist/layout/generator-js.d.ts.map +1 -0
- package/dist/layout/generator-js.js +353 -0
- package/dist/layout/generator-js.js.map +1 -0
- package/dist/layout/generator.d.ts +4 -0
- package/dist/layout/generator.d.ts.map +1 -0
- package/dist/layout/generator.js +124 -0
- package/dist/layout/generator.js.map +1 -0
- package/dist/layout/theme.d.ts +4 -0
- package/dist/layout/theme.d.ts.map +1 -0
- package/dist/layout/theme.js +28 -0
- package/dist/layout/theme.js.map +1 -0
- package/dist/layout/types.d.ts +68 -0
- package/dist/layout/types.d.ts.map +1 -0
- package/dist/layout/types.js +3 -0
- package/dist/layout/types.js.map +1 -0
- package/dist/quick/auto-layout.d.ts +5 -0
- package/dist/quick/auto-layout.d.ts.map +1 -0
- package/dist/quick/auto-layout.js +262 -0
- package/dist/quick/auto-layout.js.map +1 -0
- package/dist/quick/db/detect.d.ts +16 -0
- package/dist/quick/db/detect.d.ts.map +1 -0
- package/dist/quick/db/detect.js +131 -0
- package/dist/quick/db/detect.js.map +1 -0
- package/dist/quick/db/mongo.d.ts +10 -0
- package/dist/quick/db/mongo.d.ts.map +1 -0
- package/dist/quick/db/mongo.js +81 -0
- package/dist/quick/db/mongo.js.map +1 -0
- package/dist/quick/db/mysql.d.ts +8 -0
- package/dist/quick/db/mysql.d.ts.map +1 -0
- package/dist/quick/db/mysql.js +43 -0
- package/dist/quick/db/mysql.js.map +1 -0
- package/dist/quick/db/postgres.d.ts +8 -0
- package/dist/quick/db/postgres.d.ts.map +1 -0
- package/dist/quick/db/postgres.js +47 -0
- package/dist/quick/db/postgres.js.map +1 -0
- package/dist/quick/db/sqlite.d.ts +8 -0
- package/dist/quick/db/sqlite.d.ts.map +1 -0
- package/dist/quick/db/sqlite.js +43 -0
- package/dist/quick/db/sqlite.js.map +1 -0
- package/dist/quick/db-mode.d.ts +13 -0
- package/dist/quick/db-mode.d.ts.map +1 -0
- package/dist/quick/db-mode.js +159 -0
- package/dist/quick/db-mode.js.map +1 -0
- package/dist/quick/detect.d.ts +4 -0
- package/dist/quick/detect.d.ts.map +1 -0
- package/dist/quick/detect.js +76 -0
- package/dist/quick/detect.js.map +1 -0
- package/dist/quick/file-mode.d.ts +5 -0
- package/dist/quick/file-mode.d.ts.map +1 -0
- package/dist/quick/file-mode.js +158 -0
- package/dist/quick/file-mode.js.map +1 -0
- package/dist/quick/parsers/csv.d.ts +3 -0
- package/dist/quick/parsers/csv.d.ts.map +1 -0
- package/dist/quick/parsers/csv.js +145 -0
- package/dist/quick/parsers/csv.js.map +1 -0
- package/dist/quick/parsers/detect-meta.d.ts +7 -0
- package/dist/quick/parsers/detect-meta.d.ts.map +1 -0
- package/dist/quick/parsers/detect-meta.js +35 -0
- package/dist/quick/parsers/detect-meta.js.map +1 -0
- package/dist/quick/parsers/json.d.ts +3 -0
- package/dist/quick/parsers/json.d.ts.map +1 -0
- package/dist/quick/parsers/json.js +74 -0
- package/dist/quick/parsers/json.js.map +1 -0
- package/dist/quick/parsers/log.d.ts +3 -0
- package/dist/quick/parsers/log.d.ts.map +1 -0
- package/dist/quick/parsers/log.js +185 -0
- package/dist/quick/parsers/log.js.map +1 -0
- package/dist/quick/parsers/modsec.d.ts +3 -0
- package/dist/quick/parsers/modsec.d.ts.map +1 -0
- package/dist/quick/parsers/modsec.js +338 -0
- package/dist/quick/parsers/modsec.js.map +1 -0
- package/dist/quick/presets/coverage.d.ts +3 -0
- package/dist/quick/presets/coverage.d.ts.map +1 -0
- package/dist/quick/presets/coverage.js +362 -0
- package/dist/quick/presets/coverage.js.map +1 -0
- package/dist/quick/presets/deps.d.ts +3 -0
- package/dist/quick/presets/deps.d.ts.map +1 -0
- package/dist/quick/presets/deps.js +194 -0
- package/dist/quick/presets/deps.js.map +1 -0
- package/dist/quick/presets/docker.d.ts +3 -0
- package/dist/quick/presets/docker.d.ts.map +1 -0
- package/dist/quick/presets/docker.js +100 -0
- package/dist/quick/presets/docker.js.map +1 -0
- package/dist/quick/presets/git.d.ts +3 -0
- package/dist/quick/presets/git.d.ts.map +1 -0
- package/dist/quick/presets/git.js +116 -0
- package/dist/quick/presets/git.js.map +1 -0
- package/dist/quick/presets/ps.d.ts +3 -0
- package/dist/quick/presets/ps.d.ts.map +1 -0
- package/dist/quick/presets/ps.js +168 -0
- package/dist/quick/presets/ps.js.map +1 -0
- package/dist/quick/presets/runner.d.ts +3 -0
- package/dist/quick/presets/runner.d.ts.map +1 -0
- package/dist/quick/presets/runner.js +20 -0
- package/dist/quick/presets/runner.js.map +1 -0
- package/dist/quick/presets/types.d.ts +7 -0
- package/dist/quick/presets/types.d.ts.map +1 -0
- package/dist/quick/presets/types.js +2 -0
- package/dist/quick/presets/types.js.map +1 -0
- package/dist/quick/types.d.ts +90 -0
- package/dist/quick/types.d.ts.map +1 -0
- package/dist/quick/types.js +3 -0
- package/dist/quick/types.js.map +1 -0
- package/dist/quick/watch-mode.d.ts +3 -0
- package/dist/quick/watch-mode.d.ts.map +1 -0
- package/dist/quick/watch-mode.js +156 -0
- package/dist/quick/watch-mode.js.map +1 -0
- package/dist/server.js +2 -2
- package/dist/server.js.map +1 -1
- package/dist/types.d.ts +9 -2
- package/dist/types.d.ts.map +1 -1
- package/examples/demo.ts +134 -0
- package/examples/generate-access-log.ts +42 -0
- package/examples/screenshot-test.ts +105 -0
- package/examples/screenshot.png +0 -0
- package/frame-log.txt +830 -0
- package/package.json +10 -5
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import tuimon from '../index.js';
|
|
3
|
+
export async function startWatchModule(filePath) {
|
|
4
|
+
const resolved = path.resolve(process.cwd(), filePath);
|
|
5
|
+
let mod;
|
|
6
|
+
try {
|
|
7
|
+
mod = await import(resolved);
|
|
8
|
+
}
|
|
9
|
+
catch (err) {
|
|
10
|
+
console.error(`[tuimon] Failed to import ${filePath}:`, err);
|
|
11
|
+
process.exit(1);
|
|
12
|
+
}
|
|
13
|
+
const dataFn = mod.default ?? (typeof mod === 'function' ? mod : null);
|
|
14
|
+
if (!dataFn || typeof dataFn !== 'function') {
|
|
15
|
+
console.error(`[tuimon] ${filePath} must export a default function that returns data`);
|
|
16
|
+
process.exit(1);
|
|
17
|
+
}
|
|
18
|
+
const refresh = mod.refresh ?? 1000;
|
|
19
|
+
const title = mod.title ?? path.basename(filePath, path.extname(filePath));
|
|
20
|
+
// Get first data call to auto-detect layout
|
|
21
|
+
let firstData;
|
|
22
|
+
try {
|
|
23
|
+
firstData = await Promise.resolve(dataFn());
|
|
24
|
+
}
|
|
25
|
+
catch (err) {
|
|
26
|
+
console.error(`[tuimon] Error calling data function:`, err);
|
|
27
|
+
process.exit(1);
|
|
28
|
+
}
|
|
29
|
+
// Use module's layout or auto-detect from data shape
|
|
30
|
+
const layout = mod.layout ?? autoDetectFromData(firstData, title);
|
|
31
|
+
const dash = await tuimon.start({
|
|
32
|
+
pages: {
|
|
33
|
+
main: {
|
|
34
|
+
html: '',
|
|
35
|
+
default: true,
|
|
36
|
+
layout,
|
|
37
|
+
keys: {
|
|
38
|
+
F5: { label: 'Refresh', action: async () => { await dash.render(await Promise.resolve(dataFn())); } },
|
|
39
|
+
F10: { label: 'Quit', action: () => process.exit(0) },
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
refresh,
|
|
44
|
+
data: dataFn,
|
|
45
|
+
renderDelay: 0,
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
export async function startWatchUrl(url, interval = 1000) {
|
|
49
|
+
// Fetch first response to detect layout
|
|
50
|
+
let firstData;
|
|
51
|
+
try {
|
|
52
|
+
const res = await fetch(url);
|
|
53
|
+
firstData = await res.json();
|
|
54
|
+
}
|
|
55
|
+
catch (err) {
|
|
56
|
+
console.error(`[tuimon] Failed to fetch ${url}:`, err);
|
|
57
|
+
process.exit(1);
|
|
58
|
+
}
|
|
59
|
+
const title = new URL(url).hostname;
|
|
60
|
+
const layout = autoDetectFromData(firstData, title);
|
|
61
|
+
const dataFn = async () => {
|
|
62
|
+
const res = await fetch(url);
|
|
63
|
+
return await res.json();
|
|
64
|
+
};
|
|
65
|
+
const dash = await tuimon.start({
|
|
66
|
+
pages: {
|
|
67
|
+
main: {
|
|
68
|
+
html: '',
|
|
69
|
+
default: true,
|
|
70
|
+
layout,
|
|
71
|
+
keys: {
|
|
72
|
+
F5: { label: 'Refresh', action: async () => { await dash.render(await dataFn()); } },
|
|
73
|
+
F10: { label: 'Quit', action: () => process.exit(0) },
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
refresh: interval,
|
|
78
|
+
data: dataFn,
|
|
79
|
+
renderDelay: 0,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
// ─── Auto-detect layout from a plain data object ────────────────────────────
|
|
83
|
+
function autoDetectFromData(data, title) {
|
|
84
|
+
const stats = [];
|
|
85
|
+
const panels = [];
|
|
86
|
+
for (const [key, value] of Object.entries(data)) {
|
|
87
|
+
if (typeof value === 'number') {
|
|
88
|
+
// 0-100 → gauge, otherwise stat
|
|
89
|
+
if (value >= 0 && value <= 100 && key.match(/cpu|mem|disk|usage|percent|pct|load/i)) {
|
|
90
|
+
stats.push({ id: key, label: formatLabel(key), type: 'gauge' });
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
stats.push({ id: key, label: formatLabel(key), type: 'stat' });
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
else if (typeof value === 'string') {
|
|
97
|
+
stats.push({ id: key, label: formatLabel(key), type: 'stat' });
|
|
98
|
+
}
|
|
99
|
+
else if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
|
|
100
|
+
const obj = value;
|
|
101
|
+
// { value, trend?, unit? } → stat
|
|
102
|
+
if ('value' in obj) {
|
|
103
|
+
stats.push({ id: key, label: formatLabel(key), type: 'stat' });
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
// Record<string, number> → line chart (will accumulate)
|
|
107
|
+
const allNumbers = Object.values(obj).every((v) => typeof v === 'number');
|
|
108
|
+
if (allNumbers && Object.keys(obj).length >= 2) {
|
|
109
|
+
panels.push({ id: key, label: formatLabel(key), type: 'line', span: 2 });
|
|
110
|
+
}
|
|
111
|
+
else if (allNumbers) {
|
|
112
|
+
panels.push({ id: key, label: formatLabel(key), type: 'bar' });
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
panels.push({ id: key, label: formatLabel(key), type: 'doughnut' });
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
else if (Array.isArray(value)) {
|
|
120
|
+
if (value.length === 0)
|
|
121
|
+
continue;
|
|
122
|
+
const first = value[0];
|
|
123
|
+
if (typeof first === 'string') {
|
|
124
|
+
// Array of strings → event-log
|
|
125
|
+
panels.push({ id: key, label: formatLabel(key), type: 'event-log' });
|
|
126
|
+
}
|
|
127
|
+
else if (typeof first === 'object' && first !== null) {
|
|
128
|
+
if ('status' in first || 'label' in first) {
|
|
129
|
+
panels.push({ id: key, label: formatLabel(key), type: 'status-grid' });
|
|
130
|
+
}
|
|
131
|
+
else if ('text' in first || 'message' in first) {
|
|
132
|
+
panels.push({ id: key, label: formatLabel(key), type: 'event-log' });
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
panels.push({ id: key, label: formatLabel(key), type: 'event-log' });
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
// Move excess stats (> 6) to panels as stat
|
|
141
|
+
if (stats.length > 6) {
|
|
142
|
+
const overflow = stats.splice(6);
|
|
143
|
+
for (const s of overflow) {
|
|
144
|
+
panels.unshift(s);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return { title, stats, panels };
|
|
148
|
+
}
|
|
149
|
+
function formatLabel(key) {
|
|
150
|
+
return key
|
|
151
|
+
.replace(/([A-Z])/g, ' $1')
|
|
152
|
+
.replace(/[-_]/g, ' ')
|
|
153
|
+
.replace(/\b\w/g, (c) => c.toUpperCase())
|
|
154
|
+
.trim();
|
|
155
|
+
}
|
|
156
|
+
//# sourceMappingURL=watch-mode.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"watch-mode.js","sourceRoot":"","sources":["../../src/quick/watch-mode.ts"],"names":[],"mappings":"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"}
|
package/dist/server.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createServer } from 'node:http';
|
|
2
|
-
import { readFileSync, existsSync } from 'node:fs';
|
|
2
|
+
import { readFileSync, existsSync, statSync } from 'node:fs';
|
|
3
3
|
import { join, extname, resolve, sep } from 'node:path';
|
|
4
4
|
import { fileURLToPath } from 'node:url';
|
|
5
5
|
// ─── Paths to bundled assets ────────────────────────────────────────────────
|
|
@@ -30,7 +30,7 @@ function injectClientScript(html) {
|
|
|
30
30
|
}
|
|
31
31
|
// ─── Serve helpers ──────────────────────────────────────────────────────────
|
|
32
32
|
function serveFile(res, filePath, transform) {
|
|
33
|
-
if (!existsSync(filePath)) {
|
|
33
|
+
if (!existsSync(filePath) || statSync(filePath).isDirectory()) {
|
|
34
34
|
res.writeHead(404, { 'Content-Type': 'text/plain', Connection: 'close' });
|
|
35
35
|
res.end('Not Found');
|
|
36
36
|
return;
|
package/dist/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAA6C,MAAM,WAAW,CAAA;AACnF,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -7,7 +7,8 @@ export interface KeyBinding {
|
|
|
7
7
|
}
|
|
8
8
|
export type FKeyMap = Partial<Record<FKey, KeyBinding>>;
|
|
9
9
|
export interface PageConfig {
|
|
10
|
-
/** Absolute or cwd-relative path to the HTML file for this page
|
|
10
|
+
/** Absolute or cwd-relative path to the HTML file for this page.
|
|
11
|
+
* Required unless `layout` is provided — layout pages generate HTML automatically. */
|
|
11
12
|
html: string;
|
|
12
13
|
/** If true, this is the starting page. Exactly one page must be default. */
|
|
13
14
|
default?: boolean;
|
|
@@ -26,6 +27,9 @@ export interface PageConfig {
|
|
|
26
27
|
* and TuiMon will log a warning at startup.
|
|
27
28
|
*/
|
|
28
29
|
keys?: FKeyMap;
|
|
30
|
+
/** Declarative layout config — if provided, TuiMon generates the HTML automatically.
|
|
31
|
+
* Cannot be used together with `html` on the same page. */
|
|
32
|
+
layout?: import('./layout/types.js').LayoutConfig;
|
|
29
33
|
}
|
|
30
34
|
export type PageMap = Record<string, PageConfig>;
|
|
31
35
|
export interface TuiMonOptions {
|
|
@@ -40,7 +44,7 @@ export interface TuiMonOptions {
|
|
|
40
44
|
* Auto-render interval in ms. Requires data to be set.
|
|
41
45
|
* Default: no auto-render — developer calls dash.render() manually.
|
|
42
46
|
*/
|
|
43
|
-
refresh?: number;
|
|
47
|
+
refresh?: number | undefined;
|
|
44
48
|
/** Delay in ms after pushData() before screenshotting. Default: 50 */
|
|
45
49
|
renderDelay?: number;
|
|
46
50
|
}
|
|
@@ -87,6 +91,7 @@ export interface BrowserHandle {
|
|
|
87
91
|
pushData: (data: Record<string, unknown>) => Promise<void>;
|
|
88
92
|
navigate: (url: string) => Promise<void>;
|
|
89
93
|
resize: (width: number, height: number) => Promise<void>;
|
|
94
|
+
evaluate: (expression: string) => Promise<void>;
|
|
90
95
|
close: () => Promise<void>;
|
|
91
96
|
}
|
|
92
97
|
export interface FKeyBarHandle {
|
|
@@ -94,6 +99,8 @@ export interface FKeyBarHandle {
|
|
|
94
99
|
setKeys: (keys: FKeyMap) => void;
|
|
95
100
|
/** Show a temporary message in the bar for duration ms */
|
|
96
101
|
notify: (message: string, duration?: number) => void;
|
|
102
|
+
/** Force redraw the bar at current position */
|
|
103
|
+
redraw: () => void;
|
|
97
104
|
stop: () => void;
|
|
98
105
|
}
|
|
99
106
|
export interface KeyHandlerHandle {
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,IAAI,GACZ,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GACvC,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,CAAA;AAE9C,gEAAgE;AAChE,MAAM,MAAM,WAAW,GAAG,MAAM,CAAA;AAEhC,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CACnC;AAED,MAAM,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC,CAAA;AAIvD,MAAM,WAAW,UAAU;IACzB
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/examples/demo.ts
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
#!/usr/bin/env npx tsx
|
|
2
|
+
|
|
3
|
+
import tuimon from '../src/index.js'
|
|
4
|
+
import { cpus, freemem, totalmem, loadavg } from 'node:os'
|
|
5
|
+
|
|
6
|
+
// ─── Fake data generators ────────────────────────────────────────────────────
|
|
7
|
+
|
|
8
|
+
const logs: string[] = []
|
|
9
|
+
let reqTotal = 0
|
|
10
|
+
|
|
11
|
+
function getCpuPercent(): number {
|
|
12
|
+
const list = cpus()
|
|
13
|
+
const total = list.reduce((a, c) => a + Object.values(c.times).reduce((x, y) => x + y, 0), 0)
|
|
14
|
+
const idle = list.reduce((a, c) => a + c.times.idle, 0)
|
|
15
|
+
return Math.round(100 - (idle / total) * 100)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function getMemPercent(): number {
|
|
19
|
+
return Math.round(((totalmem() - freemem()) / totalmem()) * 100)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function formatUptime(s: number): string {
|
|
23
|
+
const h = Math.floor(s / 3600)
|
|
24
|
+
const m = Math.floor((s % 3600) / 60)
|
|
25
|
+
return `${h}h ${m}m`
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// ─── Start dashboard ─────────────────────────────────────────────────────────
|
|
29
|
+
|
|
30
|
+
const dash = await tuimon.start({
|
|
31
|
+
pages: {
|
|
32
|
+
overview: {
|
|
33
|
+
html: '', // will be overridden by layout
|
|
34
|
+
default: true,
|
|
35
|
+
label: 'Overview',
|
|
36
|
+
layout: {
|
|
37
|
+
title: 'TuiMon Demo',
|
|
38
|
+
stats: [
|
|
39
|
+
{ id: 'cpu', label: 'CPU', type: 'gauge' },
|
|
40
|
+
{ id: 'mem', label: 'Memory', type: 'gauge' },
|
|
41
|
+
{ id: 'reqs', label: 'Requests/s', type: 'stat' },
|
|
42
|
+
{ id: 'uptime', label: 'Uptime', type: 'stat' },
|
|
43
|
+
],
|
|
44
|
+
panels: [
|
|
45
|
+
{ id: 'traffic', label: 'Real-Time Traffic', type: 'line', span: 2 },
|
|
46
|
+
{ id: 'health', label: 'Node Health', type: 'status-grid', throttle: 5000 },
|
|
47
|
+
{ id: 'endpoints', label: 'Endpoint Distribution', type: 'doughnut', throttle: 3000 },
|
|
48
|
+
{ id: 'events', label: 'Recent Events', type: 'event-log', throttle: 2000 },
|
|
49
|
+
{ id: 'methods', label: 'HTTP Methods', type: 'bar', throttle: 1000 },
|
|
50
|
+
],
|
|
51
|
+
},
|
|
52
|
+
keys: {
|
|
53
|
+
F5: {
|
|
54
|
+
label: 'Force Refresh',
|
|
55
|
+
action: async () => { await dash.render(getData()) },
|
|
56
|
+
},
|
|
57
|
+
F10: {
|
|
58
|
+
label: 'Quit',
|
|
59
|
+
action: () => { process.exit(0) },
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
|
|
65
|
+
refresh: 250,
|
|
66
|
+
renderDelay: 0,
|
|
67
|
+
data: () => getData(),
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
function getData(): Record<string, unknown> {
|
|
71
|
+
const cpu = getCpuPercent()
|
|
72
|
+
const mem = getMemPercent()
|
|
73
|
+
const reqRate = Math.round(80 + Math.random() * 300)
|
|
74
|
+
reqTotal += reqRate
|
|
75
|
+
|
|
76
|
+
// Random events
|
|
77
|
+
if (Math.random() > 0.7) {
|
|
78
|
+
const events = [
|
|
79
|
+
{ text: 'Deploy completed successfully', type: 'success' as const },
|
|
80
|
+
{ text: `Request spike: ${reqRate} req/s`, type: 'warning' as const },
|
|
81
|
+
{ text: 'Health check passed', type: 'info' as const },
|
|
82
|
+
{ text: 'Cache cleared', type: 'info' as const },
|
|
83
|
+
{ text: 'Connection pool resized', type: 'warning' as const },
|
|
84
|
+
]
|
|
85
|
+
const evt = events[Math.floor(Math.random() * events.length)]!
|
|
86
|
+
logs.unshift(evt)
|
|
87
|
+
if (logs.length > 15) logs.pop()
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Simulate node health
|
|
91
|
+
const nodes = ['Node-1', 'Node-2', 'Node-3', 'Node-4', 'Node-5'].map((label) => {
|
|
92
|
+
const r = Math.random()
|
|
93
|
+
const status = r > 0.95 ? 'error' as const : r > 0.85 ? 'warn' as const : 'ok' as const
|
|
94
|
+
return { label, status }
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
return {
|
|
98
|
+
// Stats — lazy format (just numbers)
|
|
99
|
+
cpu,
|
|
100
|
+
mem,
|
|
101
|
+
reqs: { value: reqRate, trend: reqRate > 200 ? '+' + reqRate : '', unit: 'req/s' },
|
|
102
|
+
uptime: formatUptime(Math.round(process.uptime())),
|
|
103
|
+
|
|
104
|
+
// Line chart — key:value pairs, TuiMon accumulates history
|
|
105
|
+
traffic: {
|
|
106
|
+
Requests: reqRate,
|
|
107
|
+
Errors: Math.round(Math.random() * 8),
|
|
108
|
+
Latency: Math.round(20 + Math.random() * 60),
|
|
109
|
+
},
|
|
110
|
+
|
|
111
|
+
// Status grid — detailed format
|
|
112
|
+
health: nodes,
|
|
113
|
+
|
|
114
|
+
// Doughnut — key:value pairs
|
|
115
|
+
endpoints: {
|
|
116
|
+
'/api/users': 340,
|
|
117
|
+
'/api/posts': 220,
|
|
118
|
+
'/api/auth': 180,
|
|
119
|
+
'/health': 90,
|
|
120
|
+
'/ws': 45,
|
|
121
|
+
},
|
|
122
|
+
|
|
123
|
+
// Event log — detailed format
|
|
124
|
+
events: logs,
|
|
125
|
+
|
|
126
|
+
// Bar chart — key:value pairs
|
|
127
|
+
methods: {
|
|
128
|
+
GET: Math.round(200 + Math.random() * 100),
|
|
129
|
+
POST: Math.round(50 + Math.random() * 80),
|
|
130
|
+
PUT: Math.round(10 + Math.random() * 30),
|
|
131
|
+
DELETE: Math.round(5 + Math.random() * 15),
|
|
132
|
+
},
|
|
133
|
+
}
|
|
134
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
#!/usr/bin/env npx tsx
|
|
2
|
+
|
|
3
|
+
// Generates a realistic nginx access.log with 1000 entries
|
|
4
|
+
import { writeFileSync } from 'node:fs'
|
|
5
|
+
|
|
6
|
+
const methods = ['GET', 'GET', 'GET', 'GET', 'POST', 'POST', 'PUT', 'DELETE']
|
|
7
|
+
const paths = [
|
|
8
|
+
'/api/users', '/api/users/123', '/api/posts', '/api/posts/456',
|
|
9
|
+
'/api/auth/login', '/api/auth/logout', '/api/comments',
|
|
10
|
+
'/health', '/metrics', '/api/orders', '/api/products',
|
|
11
|
+
'/static/app.js', '/static/style.css', '/images/logo.png',
|
|
12
|
+
'/admin', '/admin/users', '/api/search?q=test',
|
|
13
|
+
]
|
|
14
|
+
const statuses = [200, 200, 200, 200, 200, 201, 204, 301, 304, 400, 401, 403, 404, 404, 500, 502]
|
|
15
|
+
const agents = [
|
|
16
|
+
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/120.0',
|
|
17
|
+
'Mozilla/5.0 (Macintosh; Intel Mac OS X 14_0) Safari/17.0',
|
|
18
|
+
'curl/7.88.0',
|
|
19
|
+
'PostmanRuntime/7.36.0',
|
|
20
|
+
'python-requests/2.31.0',
|
|
21
|
+
'Googlebot/2.1',
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
const lines: string[] = []
|
|
25
|
+
const baseTime = new Date('2026-04-04T10:00:00Z')
|
|
26
|
+
|
|
27
|
+
for (let i = 0; i < 1000; i++) {
|
|
28
|
+
const time = new Date(baseTime.getTime() + i * 3600) // ~1 per 3.6 seconds
|
|
29
|
+
const ip = `${10 + Math.floor(Math.random() * 240)}.${Math.floor(Math.random() * 256)}.${Math.floor(Math.random() * 256)}.${Math.floor(Math.random() * 256)}`
|
|
30
|
+
const method = methods[Math.floor(Math.random() * methods.length)]!
|
|
31
|
+
const path = paths[Math.floor(Math.random() * paths.length)]!
|
|
32
|
+
const status = statuses[Math.floor(Math.random() * statuses.length)]!
|
|
33
|
+
const bytes = Math.floor(Math.random() * 50000)
|
|
34
|
+
const agent = agents[Math.floor(Math.random() * agents.length)]!
|
|
35
|
+
const ts = time.toISOString().replace('T', ':').replace(/\.\d+Z/, ' +0000')
|
|
36
|
+
|
|
37
|
+
lines.push(`${ip} - - [${ts}] "${method} ${path} HTTP/1.1" ${status} ${bytes} "-" "${agent}"`)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const outPath = '/tmp/access.log'
|
|
41
|
+
writeFileSync(outPath, lines.join('\n') + '\n')
|
|
42
|
+
console.log(`Generated ${lines.length} log entries at ${outPath}`)
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
#!/usr/bin/env npx tsx
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Takes a screenshot of the default template with dummy data
|
|
5
|
+
* and saves it to examples/screenshot.png — open in any image viewer.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { writeFileSync, mkdirSync, writeFileSync as wf } from 'node:fs'
|
|
9
|
+
import path from 'node:path'
|
|
10
|
+
import { tmpdir } from 'node:os'
|
|
11
|
+
import { chromium } from 'playwright'
|
|
12
|
+
import { generateDashboardHtml } from '../src/layout/generator.js'
|
|
13
|
+
import type { LayoutConfig } from '../src/layout/types.js'
|
|
14
|
+
|
|
15
|
+
const layout: LayoutConfig = {
|
|
16
|
+
title: 'TuiMon Demo',
|
|
17
|
+
stats: [
|
|
18
|
+
{ id: 'cpu', label: 'CPU', type: 'gauge' },
|
|
19
|
+
{ id: 'mem', label: 'Memory', type: 'gauge' },
|
|
20
|
+
{ id: 'reqs', label: 'Requests/s', type: 'stat' },
|
|
21
|
+
{ id: 'uptime', label: 'Uptime', type: 'stat' },
|
|
22
|
+
],
|
|
23
|
+
panels: [
|
|
24
|
+
{ id: 'traffic', label: 'Real-Time Traffic', type: 'line', span: 2 },
|
|
25
|
+
{ id: 'health', label: 'Node Health', type: 'status-grid' },
|
|
26
|
+
{ id: 'endpoints', label: 'Endpoint Distribution', type: 'doughnut' },
|
|
27
|
+
{ id: 'events', label: 'Recent Events', type: 'event-log' },
|
|
28
|
+
{ id: 'methods', label: 'HTTP Methods', type: 'bar' },
|
|
29
|
+
],
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Generate HTML
|
|
33
|
+
const html = generateDashboardHtml(layout)
|
|
34
|
+
const tmpDir = path.join(tmpdir(), `tuimon-screenshot-${Date.now()}`)
|
|
35
|
+
mkdirSync(tmpDir, { recursive: true })
|
|
36
|
+
const htmlPath = path.join(tmpDir, 'dashboard.html')
|
|
37
|
+
writeFileSync(htmlPath, html, 'utf-8')
|
|
38
|
+
|
|
39
|
+
console.log('Launching browser...')
|
|
40
|
+
|
|
41
|
+
const browser = await chromium.launch({ headless: true })
|
|
42
|
+
const page = await browser.newPage()
|
|
43
|
+
await page.setViewportSize({ width: 1600, height: 900 })
|
|
44
|
+
await page.goto(`file://${htmlPath}`, { waitUntil: 'domcontentloaded' })
|
|
45
|
+
|
|
46
|
+
// Push some dummy data a few times to build chart history
|
|
47
|
+
for (let i = 0; i < 30; i++) {
|
|
48
|
+
await page.evaluate((data: Record<string, unknown>) => {
|
|
49
|
+
const win = globalThis as Record<string, unknown>
|
|
50
|
+
if (typeof win['__tuimon_update__'] === 'function') {
|
|
51
|
+
;(win['__tuimon_update__'] as (d: Record<string, unknown>) => void)(data)
|
|
52
|
+
}
|
|
53
|
+
}, {
|
|
54
|
+
cpu: 35 + Math.round(Math.random() * 40),
|
|
55
|
+
mem: 55 + Math.round(Math.random() * 20),
|
|
56
|
+
reqs: { value: Math.round(100 + Math.random() * 300), trend: '+12', unit: 'req/s' },
|
|
57
|
+
uptime: '2h 15m',
|
|
58
|
+
traffic: {
|
|
59
|
+
Requests: Math.round(100 + Math.random() * 250),
|
|
60
|
+
Errors: Math.round(Math.random() * 15),
|
|
61
|
+
Latency: Math.round(20 + Math.random() * 60),
|
|
62
|
+
},
|
|
63
|
+
health: [
|
|
64
|
+
{ label: 'Node-1', status: 'ok' },
|
|
65
|
+
{ label: 'Node-2', status: 'ok' },
|
|
66
|
+
{ label: 'Node-3', status: Math.random() > 0.5 ? 'warn' : 'ok' },
|
|
67
|
+
{ label: 'Node-4', status: 'ok' },
|
|
68
|
+
{ label: 'Node-5', status: Math.random() > 0.8 ? 'error' : 'ok' },
|
|
69
|
+
],
|
|
70
|
+
endpoints: {
|
|
71
|
+
'/api/users': 340,
|
|
72
|
+
'/api/posts': 220,
|
|
73
|
+
'/api/auth': 180,
|
|
74
|
+
'/health': 90,
|
|
75
|
+
'/ws': 45,
|
|
76
|
+
},
|
|
77
|
+
events: [
|
|
78
|
+
{ text: 'Deploy completed successfully', type: 'success', time: '2:50 PM' },
|
|
79
|
+
{ text: 'Request spike detected: 342 req/s', type: 'warning', time: '2:48 PM' },
|
|
80
|
+
{ text: 'Health check passed all nodes', type: 'info', time: '2:45 PM' },
|
|
81
|
+
{ text: 'Cache cleared — 2.3GB freed', type: 'info', time: '2:42 PM' },
|
|
82
|
+
{ text: 'Connection timeout to DB replica', type: 'error', time: '2:40 PM' },
|
|
83
|
+
{ text: 'Auto-scaled to 5 replicas', type: 'success', time: '2:38 PM' },
|
|
84
|
+
],
|
|
85
|
+
methods: {
|
|
86
|
+
GET: Math.round(200 + Math.random() * 100),
|
|
87
|
+
POST: Math.round(50 + Math.random() * 80),
|
|
88
|
+
PUT: Math.round(10 + Math.random() * 30),
|
|
89
|
+
DELETE: Math.round(5 + Math.random() * 15),
|
|
90
|
+
},
|
|
91
|
+
})
|
|
92
|
+
await new Promise((r) => setTimeout(r, 50))
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Wait for charts to render
|
|
96
|
+
await new Promise((r) => setTimeout(r, 500))
|
|
97
|
+
|
|
98
|
+
// Take screenshot
|
|
99
|
+
const outPath = path.resolve('examples/screenshot.png')
|
|
100
|
+
const buf = await page.screenshot({ type: 'png' })
|
|
101
|
+
writeFileSync(outPath, buf)
|
|
102
|
+
|
|
103
|
+
await browser.close()
|
|
104
|
+
console.log(`Screenshot saved to: ${outPath}`)
|
|
105
|
+
console.log('Open it in your image viewer or VS Code to see the dashboard.')
|
|
Binary file
|