@webda/debug 4.0.0-beta.3
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/LICENSE +166 -0
- package/README.md +95 -0
- package/lib/bodycapture.d.ts +66 -0
- package/lib/bodycapture.js +162 -0
- package/lib/bodycapture.js.map +1 -0
- package/lib/debugservice.service.d.ts +166 -0
- package/lib/debugservice.service.js +609 -0
- package/lib/debugservice.service.js.map +1 -0
- package/lib/index.d.ts +7 -0
- package/lib/index.js +7 -0
- package/lib/index.js.map +1 -0
- package/lib/introspection.d.ts +115 -0
- package/lib/introspection.js +260 -0
- package/lib/introspection.js.map +1 -0
- package/lib/logbuffer.d.ts +75 -0
- package/lib/logbuffer.js +98 -0
- package/lib/logbuffer.js.map +1 -0
- package/lib/requestlog.d.ts +181 -0
- package/lib/requestlog.js +153 -0
- package/lib/requestlog.js.map +1 -0
- package/lib/tui/client.d.ts +165 -0
- package/lib/tui/client.js +220 -0
- package/lib/tui/client.js.map +1 -0
- package/lib/tui/panels/config.d.ts +79 -0
- package/lib/tui/panels/config.js +291 -0
- package/lib/tui/panels/config.js.map +1 -0
- package/lib/tui/panels/logs.d.ts +106 -0
- package/lib/tui/panels/logs.js +342 -0
- package/lib/tui/panels/logs.js.map +1 -0
- package/lib/tui/panels/models.d.ts +47 -0
- package/lib/tui/panels/models.js +193 -0
- package/lib/tui/panels/models.js.map +1 -0
- package/lib/tui/panels/operations.d.ts +55 -0
- package/lib/tui/panels/operations.js +241 -0
- package/lib/tui/panels/operations.js.map +1 -0
- package/lib/tui/panels/panel.d.ts +55 -0
- package/lib/tui/panels/panel.js +31 -0
- package/lib/tui/panels/panel.js.map +1 -0
- package/lib/tui/panels/requests.d.ts +156 -0
- package/lib/tui/panels/requests.js +512 -0
- package/lib/tui/panels/requests.js.map +1 -0
- package/lib/tui/panels/routes.d.ts +45 -0
- package/lib/tui/panels/routes.js +154 -0
- package/lib/tui/panels/routes.js.map +1 -0
- package/lib/tui/panels/services.d.ts +49 -0
- package/lib/tui/panels/services.js +266 -0
- package/lib/tui/panels/services.js.map +1 -0
- package/lib/tui/tui.d.ts +58 -0
- package/lib/tui/tui.js +236 -0
- package/lib/tui/tui.js.map +1 -0
- package/package.json +60 -0
- package/webui/app.js +177 -0
- package/webui/components/logs.js +128 -0
- package/webui/components/model-graph.js +292 -0
- package/webui/components/models.js +213 -0
- package/webui/components/operations.js +315 -0
- package/webui/components/requests.js +264 -0
- package/webui/components/schema-form.js +268 -0
- package/webui/components/services.js +248 -0
- package/webui/index.html +22 -0
- package/webui/logo.svg +1 -0
- package/webui/styles.css +685 -0
- package/webui/vendor/htm.js +1 -0
- package/webui/vendor/preact-hooks.js +2 -0
- package/webui/vendor/preact.js +2 -0
- package/webui/webda.png +0 -0
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import { WebSocket } from "ws";
|
|
2
|
+
/**
|
|
3
|
+
* HTTP + WebSocket client for the debug server API.
|
|
4
|
+
*
|
|
5
|
+
* Connects to the debug server started by `webda debug` and provides
|
|
6
|
+
* typed methods for each introspection endpoint, plus a reconnecting
|
|
7
|
+
* WebSocket subscription for live request events.
|
|
8
|
+
*/
|
|
9
|
+
export class DebugClient {
|
|
10
|
+
/**
|
|
11
|
+
* Creates a new DebugClient.
|
|
12
|
+
*
|
|
13
|
+
* @param baseUrl - Base URL of the debug server, e.g. "http://localhost:18181"
|
|
14
|
+
*/
|
|
15
|
+
constructor(baseUrl = "http://localhost:18181") {
|
|
16
|
+
/** Whether the client should try to reconnect */
|
|
17
|
+
this.shouldReconnect = false;
|
|
18
|
+
/** Current reconnect delay in ms */
|
|
19
|
+
this.reconnectDelay = 1000;
|
|
20
|
+
/** Maximum reconnect delay in ms */
|
|
21
|
+
this.maxReconnectDelay = 30000;
|
|
22
|
+
/** Event subscribers */
|
|
23
|
+
this.subscribers = new Set();
|
|
24
|
+
/** Connection status */
|
|
25
|
+
this._connected = false;
|
|
26
|
+
this.baseUrl = baseUrl.replace(/\/$/, "");
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Whether the WebSocket is currently connected.
|
|
30
|
+
* @returns true if the WebSocket connection is open
|
|
31
|
+
*/
|
|
32
|
+
get connected() {
|
|
33
|
+
return this._connected;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Fetch parsed JSON from a debug API endpoint.
|
|
37
|
+
*
|
|
38
|
+
* @param path - API path starting with /
|
|
39
|
+
* @returns Parsed JSON response
|
|
40
|
+
*/
|
|
41
|
+
async fetchJson(path) {
|
|
42
|
+
const res = await fetch(`${this.baseUrl}${path}`);
|
|
43
|
+
if (!res.ok) {
|
|
44
|
+
throw new Error(`HTTP ${res.status}: ${res.statusText}`);
|
|
45
|
+
}
|
|
46
|
+
return res.json();
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Fetch all registered models.
|
|
50
|
+
* @returns array of model metadata objects
|
|
51
|
+
*/
|
|
52
|
+
async getModels() {
|
|
53
|
+
return this.fetchJson("/api/models");
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Fetch a single model by identifier.
|
|
57
|
+
*
|
|
58
|
+
* @param id - Fully-qualified model identifier
|
|
59
|
+
* @returns model metadata object
|
|
60
|
+
*/
|
|
61
|
+
async getModel(id) {
|
|
62
|
+
return this.fetchJson(`/api/models/${encodeURIComponent(id)}`);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Fetch all registered services.
|
|
66
|
+
* @returns array of service info objects
|
|
67
|
+
*/
|
|
68
|
+
async getServices() {
|
|
69
|
+
return this.fetchJson("/api/services");
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Fetch all registered operations.
|
|
73
|
+
* @returns array of operation info objects
|
|
74
|
+
*/
|
|
75
|
+
async getOperations() {
|
|
76
|
+
return this.fetchJson("/api/operations");
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Fetch all registered routes.
|
|
80
|
+
* @returns array of route info objects
|
|
81
|
+
*/
|
|
82
|
+
async getRoutes() {
|
|
83
|
+
return this.fetchJson("/api/routes");
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Fetch the resolved application configuration.
|
|
87
|
+
* @returns resolved configuration record
|
|
88
|
+
*/
|
|
89
|
+
async getConfig() {
|
|
90
|
+
return this.fetchJson("/api/config");
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Fetch the OpenAPI specification.
|
|
94
|
+
* @returns OpenAPI 3.0.3 document
|
|
95
|
+
*/
|
|
96
|
+
async getOpenAPI() {
|
|
97
|
+
return this.fetchJson("/api/openapi");
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Fetch recent request log entries (summary fields only — no headers/bodies).
|
|
101
|
+
* @returns array of request log entry summaries
|
|
102
|
+
*/
|
|
103
|
+
async getRequests() {
|
|
104
|
+
return this.fetchJson("/api/requests");
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Fetch the full detail of a single request by id, including captured
|
|
108
|
+
* headers, bodies, and any error.
|
|
109
|
+
*
|
|
110
|
+
* @param id - The request id (as returned in the summary list).
|
|
111
|
+
* @returns The detailed request entry.
|
|
112
|
+
*/
|
|
113
|
+
async getRequestDetail(id) {
|
|
114
|
+
return this.fetchJson(`/api/requests/${encodeURIComponent(id)}`);
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Fetch recent application log entries.
|
|
118
|
+
* @returns array of log entries
|
|
119
|
+
*/
|
|
120
|
+
async getLogs() {
|
|
121
|
+
return this.fetchJson("/api/logs");
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Fetch application info (package name, version, working directory).
|
|
125
|
+
* @returns project information record
|
|
126
|
+
*/
|
|
127
|
+
async getAppInfo() {
|
|
128
|
+
return this.fetchJson("/api/info");
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Search application log entries by query string.
|
|
132
|
+
*
|
|
133
|
+
* @param query - search text to filter logs
|
|
134
|
+
* @returns array of matching log entries
|
|
135
|
+
*/
|
|
136
|
+
async searchLogs(query) {
|
|
137
|
+
return this.fetchJson(`/api/logs?q=${encodeURIComponent(query)}`);
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Subscribe to WebSocket events.
|
|
141
|
+
*
|
|
142
|
+
* @param callback - Called for each event received
|
|
143
|
+
* @returns Unsubscribe function
|
|
144
|
+
*/
|
|
145
|
+
onEvent(callback) {
|
|
146
|
+
this.subscribers.add(callback);
|
|
147
|
+
return () => this.subscribers.delete(callback);
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Connect to the debug server WebSocket and begin receiving events.
|
|
151
|
+
* Automatically reconnects with exponential backoff on disconnect.
|
|
152
|
+
*/
|
|
153
|
+
connectWebSocket() {
|
|
154
|
+
this.shouldReconnect = true;
|
|
155
|
+
this.doConnect();
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Internal: establish the WebSocket connection.
|
|
159
|
+
*/
|
|
160
|
+
doConnect() {
|
|
161
|
+
const wsUrl = this.baseUrl.replace(/^http/, "ws") + "/ws";
|
|
162
|
+
try {
|
|
163
|
+
this.ws = new WebSocket(wsUrl);
|
|
164
|
+
}
|
|
165
|
+
catch {
|
|
166
|
+
this.scheduleReconnect();
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
this.ws.on("open", () => {
|
|
170
|
+
this._connected = true;
|
|
171
|
+
this.reconnectDelay = 1000;
|
|
172
|
+
});
|
|
173
|
+
this.ws.on("message", (data) => {
|
|
174
|
+
try {
|
|
175
|
+
const event = JSON.parse(data.toString());
|
|
176
|
+
for (const cb of this.subscribers) {
|
|
177
|
+
cb(event);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
catch {
|
|
181
|
+
// Ignore malformed messages
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
this.ws.on("close", () => {
|
|
185
|
+
this._connected = false;
|
|
186
|
+
this.scheduleReconnect();
|
|
187
|
+
});
|
|
188
|
+
this.ws.on("error", () => {
|
|
189
|
+
this._connected = false;
|
|
190
|
+
// close event will fire after error, triggering reconnect
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Schedule a reconnection attempt with exponential backoff.
|
|
195
|
+
*/
|
|
196
|
+
scheduleReconnect() {
|
|
197
|
+
if (!this.shouldReconnect)
|
|
198
|
+
return;
|
|
199
|
+
this.reconnectTimer = setTimeout(() => {
|
|
200
|
+
this.reconnectDelay = Math.min(this.reconnectDelay * 2, this.maxReconnectDelay);
|
|
201
|
+
this.doConnect();
|
|
202
|
+
}, this.reconnectDelay);
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Disconnect the WebSocket and stop reconnecting.
|
|
206
|
+
*/
|
|
207
|
+
disconnect() {
|
|
208
|
+
this.shouldReconnect = false;
|
|
209
|
+
if (this.reconnectTimer) {
|
|
210
|
+
clearTimeout(this.reconnectTimer);
|
|
211
|
+
this.reconnectTimer = undefined;
|
|
212
|
+
}
|
|
213
|
+
if (this.ws) {
|
|
214
|
+
this.ws.close();
|
|
215
|
+
this.ws = undefined;
|
|
216
|
+
}
|
|
217
|
+
this._connected = false;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/tui/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import type { Panel } from "./panel.js";
|
|
2
|
+
import type { DebugClient } from "../client.js";
|
|
3
|
+
/**
|
|
4
|
+
* Config panel: displays the resolved application configuration
|
|
5
|
+
* as an interactive, collapsible JSON tree with syntax highlighting.
|
|
6
|
+
*
|
|
7
|
+
* Navigate with Up/Down arrows, toggle collapse with Enter or Space.
|
|
8
|
+
* Top-level keys start expanded; deeper levels start collapsed.
|
|
9
|
+
*/
|
|
10
|
+
export declare class ConfigPanel implements Panel {
|
|
11
|
+
private client;
|
|
12
|
+
name: string;
|
|
13
|
+
private nodes;
|
|
14
|
+
private collapsed;
|
|
15
|
+
private cursor;
|
|
16
|
+
private scrollOffset;
|
|
17
|
+
private visibleRows;
|
|
18
|
+
/**
|
|
19
|
+
* @param client - Debug API client
|
|
20
|
+
*/
|
|
21
|
+
constructor(client: DebugClient);
|
|
22
|
+
/**
|
|
23
|
+
* Fetch configuration and build the tree.
|
|
24
|
+
*/
|
|
25
|
+
refresh(): Promise<void>;
|
|
26
|
+
/**
|
|
27
|
+
* Recursively build a flat list of tree nodes from a JSON value.
|
|
28
|
+
*
|
|
29
|
+
* @param obj - The value to process
|
|
30
|
+
* @param depth - Current nesting depth
|
|
31
|
+
* @param parentPath - Dot-separated path of the parent
|
|
32
|
+
* @param key - Property name if this is an object property
|
|
33
|
+
* @param index - Array index if this is an array element
|
|
34
|
+
*/
|
|
35
|
+
private buildTree;
|
|
36
|
+
/**
|
|
37
|
+
* Compute the list of visible nodes by filtering out
|
|
38
|
+
* children of collapsed nodes.
|
|
39
|
+
*
|
|
40
|
+
* @returns array of nodes that should be rendered
|
|
41
|
+
*/
|
|
42
|
+
private getVisibleNodes;
|
|
43
|
+
/**
|
|
44
|
+
* Handle keyboard input for navigation and toggling.
|
|
45
|
+
*
|
|
46
|
+
* @param key - key name from terminal-kit
|
|
47
|
+
*/
|
|
48
|
+
onKey(key: string): void;
|
|
49
|
+
/**
|
|
50
|
+
* Render the JSON tree with syntax highlighting and collapse indicators.
|
|
51
|
+
*
|
|
52
|
+
* @param term - terminal-kit instance
|
|
53
|
+
* @param startRow - first available row
|
|
54
|
+
* @param endRow - last available row
|
|
55
|
+
* @param width - terminal width in columns
|
|
56
|
+
*/
|
|
57
|
+
render(term: any, startRow: number, endRow: number, width: number): void;
|
|
58
|
+
/**
|
|
59
|
+
* Render a single tree node with indentation, collapse indicator,
|
|
60
|
+
* key, and value with syntax-highlighted colors.
|
|
61
|
+
*
|
|
62
|
+
* @param term - terminal-kit instance
|
|
63
|
+
* @param node - the tree node to render
|
|
64
|
+
* @param width - terminal width
|
|
65
|
+
* @param highlighted - whether this line is the cursor line
|
|
66
|
+
*/
|
|
67
|
+
private renderNode;
|
|
68
|
+
/**
|
|
69
|
+
* Render a leaf value with type-appropriate coloring.
|
|
70
|
+
*
|
|
71
|
+
* @param term - terminal-kit instance
|
|
72
|
+
* @param value - the value to render
|
|
73
|
+
*/
|
|
74
|
+
private renderValue;
|
|
75
|
+
/**
|
|
76
|
+
* Clean up panel resources.
|
|
77
|
+
*/
|
|
78
|
+
destroy(): void;
|
|
79
|
+
}
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Config panel: displays the resolved application configuration
|
|
3
|
+
* as an interactive, collapsible JSON tree with syntax highlighting.
|
|
4
|
+
*
|
|
5
|
+
* Navigate with Up/Down arrows, toggle collapse with Enter or Space.
|
|
6
|
+
* Top-level keys start expanded; deeper levels start collapsed.
|
|
7
|
+
*/
|
|
8
|
+
export class ConfigPanel {
|
|
9
|
+
/**
|
|
10
|
+
* @param client - Debug API client
|
|
11
|
+
*/
|
|
12
|
+
constructor(client) {
|
|
13
|
+
this.client = client;
|
|
14
|
+
this.name = "Config";
|
|
15
|
+
this.nodes = [];
|
|
16
|
+
this.collapsed = new Set();
|
|
17
|
+
this.cursor = 0;
|
|
18
|
+
this.scrollOffset = 0;
|
|
19
|
+
this.visibleRows = 0;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Fetch configuration and build the tree.
|
|
23
|
+
*/
|
|
24
|
+
async refresh() {
|
|
25
|
+
try {
|
|
26
|
+
const config = await this.client.getConfig();
|
|
27
|
+
this.nodes = [];
|
|
28
|
+
this.collapsed = new Set();
|
|
29
|
+
this.buildTree(config, 0, "root");
|
|
30
|
+
this.cursor = Math.min(this.cursor, Math.max(0, this.getVisibleNodes().length - 1));
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
this.nodes = [];
|
|
34
|
+
this.collapsed = new Set();
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Recursively build a flat list of tree nodes from a JSON value.
|
|
39
|
+
*
|
|
40
|
+
* @param obj - The value to process
|
|
41
|
+
* @param depth - Current nesting depth
|
|
42
|
+
* @param parentPath - Dot-separated path of the parent
|
|
43
|
+
* @param key - Property name if this is an object property
|
|
44
|
+
* @param index - Array index if this is an array element
|
|
45
|
+
*/
|
|
46
|
+
buildTree(obj, depth, parentPath, key, index) {
|
|
47
|
+
const pathSegment = key !== undefined ? key : index !== undefined ? String(index) : "root";
|
|
48
|
+
const path = parentPath === "" ? pathSegment : `${parentPath}.${pathSegment}`;
|
|
49
|
+
const isObject = obj !== null && typeof obj === "object" && !Array.isArray(obj);
|
|
50
|
+
const isArray = Array.isArray(obj);
|
|
51
|
+
const hasChildren = isObject || isArray;
|
|
52
|
+
const childCount = hasChildren ? (isArray ? obj.length : Object.keys(obj).length) : 0;
|
|
53
|
+
const node = {
|
|
54
|
+
key,
|
|
55
|
+
index,
|
|
56
|
+
value: obj,
|
|
57
|
+
depth,
|
|
58
|
+
collapsed: false,
|
|
59
|
+
hasChildren,
|
|
60
|
+
path,
|
|
61
|
+
childCount,
|
|
62
|
+
isArray
|
|
63
|
+
};
|
|
64
|
+
this.nodes.push(node);
|
|
65
|
+
if (hasChildren) {
|
|
66
|
+
if (isArray) {
|
|
67
|
+
for (let i = 0; i < obj.length; i++) {
|
|
68
|
+
this.buildTree(obj[i], depth + 1, path, undefined, i);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
const keys = Object.keys(obj);
|
|
73
|
+
for (const k of keys) {
|
|
74
|
+
this.buildTree(obj[k], depth + 1, path, k);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Compute the list of visible nodes by filtering out
|
|
81
|
+
* children of collapsed nodes.
|
|
82
|
+
*
|
|
83
|
+
* @returns array of nodes that should be rendered
|
|
84
|
+
*/
|
|
85
|
+
getVisibleNodes() {
|
|
86
|
+
const visible = [];
|
|
87
|
+
let skipUntilDepth = -1;
|
|
88
|
+
for (const node of this.nodes) {
|
|
89
|
+
// If we are skipping children of a collapsed node
|
|
90
|
+
if (skipUntilDepth >= 0 && node.depth > skipUntilDepth) {
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
skipUntilDepth = -1;
|
|
94
|
+
visible.push(node);
|
|
95
|
+
// If this node is collapsed, skip its children
|
|
96
|
+
if (node.hasChildren && this.collapsed.has(node.path)) {
|
|
97
|
+
skipUntilDepth = node.depth;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return visible;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Handle keyboard input for navigation and toggling.
|
|
104
|
+
*
|
|
105
|
+
* @param key - key name from terminal-kit
|
|
106
|
+
*/
|
|
107
|
+
onKey(key) {
|
|
108
|
+
const visible = this.getVisibleNodes();
|
|
109
|
+
if (visible.length === 0)
|
|
110
|
+
return;
|
|
111
|
+
switch (key) {
|
|
112
|
+
case "UP":
|
|
113
|
+
if (this.cursor > 0)
|
|
114
|
+
this.cursor--;
|
|
115
|
+
break;
|
|
116
|
+
case "DOWN":
|
|
117
|
+
if (this.cursor < visible.length - 1)
|
|
118
|
+
this.cursor++;
|
|
119
|
+
break;
|
|
120
|
+
case "PAGE_UP":
|
|
121
|
+
this.cursor = Math.max(0, this.cursor - this.visibleRows);
|
|
122
|
+
break;
|
|
123
|
+
case "PAGE_DOWN":
|
|
124
|
+
this.cursor = Math.min(visible.length - 1, this.cursor + this.visibleRows);
|
|
125
|
+
break;
|
|
126
|
+
case "HOME":
|
|
127
|
+
this.cursor = 0;
|
|
128
|
+
this.scrollOffset = 0;
|
|
129
|
+
break;
|
|
130
|
+
case "END":
|
|
131
|
+
this.cursor = visible.length - 1;
|
|
132
|
+
break;
|
|
133
|
+
case "ENTER":
|
|
134
|
+
case " ": {
|
|
135
|
+
const node = visible[this.cursor];
|
|
136
|
+
if (node?.hasChildren) {
|
|
137
|
+
if (this.collapsed.has(node.path)) {
|
|
138
|
+
this.collapsed.delete(node.path);
|
|
139
|
+
node.collapsed = false;
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
this.collapsed.add(node.path);
|
|
143
|
+
node.collapsed = true;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
break;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
// Adjust scroll to keep cursor visible
|
|
150
|
+
if (this.cursor < this.scrollOffset) {
|
|
151
|
+
this.scrollOffset = this.cursor;
|
|
152
|
+
}
|
|
153
|
+
else if (this.cursor >= this.scrollOffset + this.visibleRows) {
|
|
154
|
+
this.scrollOffset = this.cursor - this.visibleRows + 1;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Render the JSON tree with syntax highlighting and collapse indicators.
|
|
159
|
+
*
|
|
160
|
+
* @param term - terminal-kit instance
|
|
161
|
+
* @param startRow - first available row
|
|
162
|
+
* @param endRow - last available row
|
|
163
|
+
* @param width - terminal width in columns
|
|
164
|
+
*/
|
|
165
|
+
render(term, startRow, endRow, width) {
|
|
166
|
+
this.visibleRows = endRow - startRow;
|
|
167
|
+
if (this.nodes.length === 0) {
|
|
168
|
+
term.moveTo(1, startRow);
|
|
169
|
+
term.eraseLine();
|
|
170
|
+
term(" No configuration loaded.");
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
const visible = this.getVisibleNodes();
|
|
174
|
+
// Clamp cursor/scroll in case the tree changed
|
|
175
|
+
if (this.cursor >= visible.length) {
|
|
176
|
+
this.cursor = Math.max(0, visible.length - 1);
|
|
177
|
+
}
|
|
178
|
+
if (this.scrollOffset > this.cursor) {
|
|
179
|
+
this.scrollOffset = this.cursor;
|
|
180
|
+
}
|
|
181
|
+
for (let i = 0; i < this.visibleRows; i++) {
|
|
182
|
+
const idx = this.scrollOffset + i;
|
|
183
|
+
const row = startRow + i;
|
|
184
|
+
term.moveTo(1, row);
|
|
185
|
+
term.eraseLine();
|
|
186
|
+
if (idx >= visible.length)
|
|
187
|
+
continue;
|
|
188
|
+
const node = visible[idx];
|
|
189
|
+
const isCurrent = idx === this.cursor;
|
|
190
|
+
if (isCurrent) {
|
|
191
|
+
term.bgGray();
|
|
192
|
+
}
|
|
193
|
+
this.renderNode(term, node, width, isCurrent);
|
|
194
|
+
if (isCurrent) {
|
|
195
|
+
// Fill rest of line with highlight background
|
|
196
|
+
term.styleReset();
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Render a single tree node with indentation, collapse indicator,
|
|
202
|
+
* key, and value with syntax-highlighted colors.
|
|
203
|
+
*
|
|
204
|
+
* @param term - terminal-kit instance
|
|
205
|
+
* @param node - the tree node to render
|
|
206
|
+
* @param width - terminal width
|
|
207
|
+
* @param highlighted - whether this line is the cursor line
|
|
208
|
+
*/
|
|
209
|
+
renderNode(term, node, width, highlighted) {
|
|
210
|
+
const indent = " ".repeat(node.depth);
|
|
211
|
+
term(indent);
|
|
212
|
+
if (node.hasChildren) {
|
|
213
|
+
// Collapse indicator
|
|
214
|
+
const indicator = this.collapsed.has(node.path) ? "\u25B6 " : "\u25BC ";
|
|
215
|
+
term.white(indicator);
|
|
216
|
+
// Key or index label
|
|
217
|
+
if (node.key !== undefined) {
|
|
218
|
+
term.cyan(node.key);
|
|
219
|
+
term(": ");
|
|
220
|
+
}
|
|
221
|
+
else if (node.index !== undefined) {
|
|
222
|
+
term.dim(`[${node.index}]`);
|
|
223
|
+
term(": ");
|
|
224
|
+
}
|
|
225
|
+
// Collapsed summary or opening bracket
|
|
226
|
+
if (this.collapsed.has(node.path)) {
|
|
227
|
+
if (node.isArray) {
|
|
228
|
+
term.dim(`[...] (${node.childCount} items)`);
|
|
229
|
+
}
|
|
230
|
+
else {
|
|
231
|
+
term.dim(`{...} (${node.childCount} keys)`);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
else {
|
|
235
|
+
term.dim(node.isArray ? "[" : "{");
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
else {
|
|
239
|
+
// Leaf node: spaces in place of collapse indicator
|
|
240
|
+
term(" ");
|
|
241
|
+
// Key or index label
|
|
242
|
+
if (node.key !== undefined) {
|
|
243
|
+
term.cyan(node.key);
|
|
244
|
+
term(": ");
|
|
245
|
+
}
|
|
246
|
+
else if (node.index !== undefined) {
|
|
247
|
+
term.dim(`[${node.index}]`);
|
|
248
|
+
term(": ");
|
|
249
|
+
}
|
|
250
|
+
// Value with type-appropriate color
|
|
251
|
+
this.renderValue(term, node.value);
|
|
252
|
+
}
|
|
253
|
+
if (highlighted) {
|
|
254
|
+
term.styleReset();
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Render a leaf value with type-appropriate coloring.
|
|
259
|
+
*
|
|
260
|
+
* @param term - terminal-kit instance
|
|
261
|
+
* @param value - the value to render
|
|
262
|
+
*/
|
|
263
|
+
renderValue(term, value) {
|
|
264
|
+
if (value === null) {
|
|
265
|
+
term.red("null");
|
|
266
|
+
}
|
|
267
|
+
else if (value === undefined) {
|
|
268
|
+
term.red("undefined");
|
|
269
|
+
}
|
|
270
|
+
else if (typeof value === "string") {
|
|
271
|
+
term.green(`"${value}"`);
|
|
272
|
+
}
|
|
273
|
+
else if (typeof value === "number") {
|
|
274
|
+
term.yellow(String(value));
|
|
275
|
+
}
|
|
276
|
+
else if (typeof value === "boolean") {
|
|
277
|
+
term.magenta(String(value));
|
|
278
|
+
}
|
|
279
|
+
else {
|
|
280
|
+
term(String(value));
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Clean up panel resources.
|
|
285
|
+
*/
|
|
286
|
+
destroy() {
|
|
287
|
+
this.nodes = [];
|
|
288
|
+
this.collapsed.clear();
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../../src/tui/panels/config.ts"],"names":[],"mappings":"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"}
|