@tsplc/debug 0.2.17 → 0.2.19
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/format.js +36 -18
- package/dist/format.js.map +4 -4
- package/dist/index.js +768 -516
- package/dist/index.js.map +20 -17
- package/dist/manifest.js +6 -2
- package/dist/manifest.js.map +3 -3
- package/dist/paths.js +60 -28
- package/dist/paths.js.map +3 -3
- package/package.json +47 -46
- package/src/adapter.ts +43 -36
- package/src/api.ts +126 -123
- package/src/debugger.ts +584 -467
- package/src/errors.ts +3 -0
- package/src/hardware.ts +127 -96
- package/src/http.ts +147 -116
- package/src/index.ts +34 -4
- package/src/jobs.ts +102 -77
- package/src/login-value.ts +165 -0
- package/src/login.ts +233 -253
- package/src/manifest.ts +200 -194
- package/src/opcua.ts +55 -55
- package/src/paths.ts +230 -157
- package/src/requests.ts +86 -0
- package/src/telemetry.ts +104 -90
- package/src/timeline.ts +96 -61
- package/src/trace.ts +41 -31
- package/src/ui/bits.ts +45 -29
- package/src/ui/client.ts +33 -26
- package/src/ui/dom.ts +189 -108
- package/src/ui/format.ts +127 -72
- package/src/ui/hardware.ts +416 -343
- package/src/ui/header.ts +186 -164
- package/src/ui/index.ts +16 -9
- package/src/ui/jobs.ts +263 -214
- package/src/ui/main.ts +52 -48
- package/src/ui/overview.ts +152 -108
- package/src/ui/recent.ts +329 -276
- package/src/ui/requests.ts +69 -73
- package/src/ui/store.ts +236 -198
- package/src/ui/tree.ts +162 -130
- package/src/ui/variables.ts +557 -431
- package/src/watch.ts +22 -17
- package/src/ui/dev.ts +0 -579
- package/src/ui/fixture.ts +0 -548
package/src/ui/recent.ts
CHANGED
|
@@ -1,7 +1,19 @@
|
|
|
1
1
|
import type { AppRecord, TimelineEntry, TraceEvent } from "../api.ts";
|
|
2
2
|
import type { DebugEventSite, DebugManifest } from "../manifest.ts";
|
|
3
|
-
import {
|
|
4
|
-
|
|
3
|
+
import {
|
|
4
|
+
type View,
|
|
5
|
+
empty,
|
|
6
|
+
h,
|
|
7
|
+
pathLink,
|
|
8
|
+
recordSourceLink,
|
|
9
|
+
sourceLink,
|
|
10
|
+
} from "./dom.ts";
|
|
11
|
+
import {
|
|
12
|
+
formatClock,
|
|
13
|
+
formatDuration,
|
|
14
|
+
formatProperties,
|
|
15
|
+
formatValue,
|
|
16
|
+
} from "./format.ts";
|
|
5
17
|
import { requestJobLink, requestStatus } from "./jobs.ts";
|
|
6
18
|
import type { Store } from "./store.ts";
|
|
7
19
|
|
|
@@ -11,14 +23,14 @@ type Kind = AppRecord["kind"] | Exclude<TimelineEntry["kind"], "app">;
|
|
|
11
23
|
|
|
12
24
|
const SOURCES: Source[] = ["plc", "server", "agent", "debugger"];
|
|
13
25
|
const KINDS: Kind[] = [
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
26
|
+
"event",
|
|
27
|
+
"log",
|
|
28
|
+
"exception",
|
|
29
|
+
"trace",
|
|
30
|
+
"request",
|
|
31
|
+
"deploy",
|
|
32
|
+
"audit",
|
|
33
|
+
"connection",
|
|
22
34
|
];
|
|
23
35
|
const PAGE = 300;
|
|
24
36
|
const RENDER_INTERVAL_MS = 300;
|
|
@@ -27,296 +39,337 @@ const hiddenSources = new Set<Source>();
|
|
|
27
39
|
const hiddenKinds = new Set<Kind>();
|
|
28
40
|
|
|
29
41
|
const kindOf = (entry: TimelineEntry): Kind =>
|
|
30
|
-
|
|
42
|
+
entry.kind === "app" ? entry.record.kind : entry.kind;
|
|
31
43
|
|
|
32
|
-
const sitesByManifest = new WeakMap<
|
|
44
|
+
const sitesByManifest = new WeakMap<
|
|
45
|
+
DebugManifest,
|
|
46
|
+
Map<number, DebugEventSite>
|
|
47
|
+
>();
|
|
33
48
|
const siteOf = (manifest: DebugManifest, id: number) => {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
49
|
+
let sites = sitesByManifest.get(manifest);
|
|
50
|
+
if (!sites) {
|
|
51
|
+
sites = new Map(manifest.events.map((site) => [site.id, site]));
|
|
52
|
+
sitesByManifest.set(manifest, sites);
|
|
53
|
+
}
|
|
54
|
+
return sites.get(id);
|
|
40
55
|
};
|
|
41
56
|
|
|
42
57
|
/** A traced write, worded as what was observed: the value, the scan, and the guards captured with it. */
|
|
43
58
|
const traceBody = (store: Store, trace: TraceEvent) => {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
59
|
+
const site = siteOf(store.manifest, trace.site);
|
|
60
|
+
if (!site) {
|
|
61
|
+
return [
|
|
62
|
+
h(
|
|
63
|
+
"div",
|
|
64
|
+
{},
|
|
65
|
+
`Site ${trace.site} is not in this build's manifest; value ${JSON.stringify(trace.value)} in scan ${trace.scan}.`,
|
|
66
|
+
),
|
|
67
|
+
];
|
|
68
|
+
}
|
|
69
|
+
return [
|
|
70
|
+
h(
|
|
71
|
+
"div",
|
|
72
|
+
{},
|
|
73
|
+
h("span", { class: "tag" }, site.kind),
|
|
74
|
+
" ",
|
|
75
|
+
pathLink(site.path),
|
|
76
|
+
" was ",
|
|
77
|
+
h(
|
|
78
|
+
"b",
|
|
79
|
+
{ class: "val" },
|
|
80
|
+
formatValue(store.manifest, site.type, trace.value),
|
|
81
|
+
),
|
|
82
|
+
` in scan ${trace.scan}`,
|
|
83
|
+
h("span", { class: "dim" }, ` · ${trace.task}`),
|
|
84
|
+
),
|
|
85
|
+
h("div", {}, h("code", {}, site.text), " ", sourceLink(store, site.range)),
|
|
86
|
+
trace.operands.length > 0 &&
|
|
87
|
+
h(
|
|
88
|
+
"div",
|
|
89
|
+
{ class: "chips" },
|
|
90
|
+
h("span", { class: "dim" }, "guards in that scan "),
|
|
91
|
+
...trace.operands.map((operand, index) => {
|
|
92
|
+
const declared = site.operands[index];
|
|
93
|
+
const value = declared
|
|
94
|
+
? formatValue(store.manifest, declared.type, operand.value)
|
|
95
|
+
: JSON.stringify(operand.value);
|
|
96
|
+
return h(
|
|
97
|
+
"span",
|
|
98
|
+
{
|
|
99
|
+
class: `chip${operand.stable ? "" : " unstable"}`,
|
|
100
|
+
title: operand.stable
|
|
101
|
+
? `${operand.text}, captured at the write`
|
|
102
|
+
: `${operand.text}, captured at the write; code between the guard and the write can change it, so the guard may have seen another value`,
|
|
103
|
+
},
|
|
104
|
+
declared
|
|
105
|
+
? sourceLink(store, declared.range, operand.text)
|
|
106
|
+
: h("code", {}, operand.text),
|
|
107
|
+
" = ",
|
|
108
|
+
operand.path
|
|
109
|
+
? pathLink(operand.path, value)
|
|
110
|
+
: h("span", { class: "val" }, value),
|
|
111
|
+
operand.stable ? "" : h("span", { class: "dim" }, " ~"),
|
|
112
|
+
);
|
|
113
|
+
}),
|
|
114
|
+
),
|
|
115
|
+
];
|
|
94
116
|
};
|
|
95
117
|
|
|
96
118
|
/** What the program reported: `bin scanned · barcode=CON-MD3… scanner=3 · route-lookup.ts:120`. */
|
|
97
119
|
const appBody = (store: Store, task: string, record: AppRecord) => {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
120
|
+
const properties = Object.keys(record.properties).length
|
|
121
|
+
? h(
|
|
122
|
+
"span",
|
|
123
|
+
{ class: "mono", title: JSON.stringify(record.properties, null, 1) },
|
|
124
|
+
` · ${formatProperties(record.properties)}`,
|
|
125
|
+
)
|
|
126
|
+
: "";
|
|
127
|
+
const origin = [
|
|
128
|
+
" · ",
|
|
129
|
+
recordSourceLink(store, record.source),
|
|
130
|
+
h("span", { class: "dim" }, ` · ${task}`),
|
|
131
|
+
];
|
|
132
|
+
switch (record.kind) {
|
|
133
|
+
case "event":
|
|
134
|
+
return [h("div", {}, h("b", {}, record.event), properties, ...origin)];
|
|
135
|
+
case "log":
|
|
136
|
+
return [
|
|
137
|
+
h(
|
|
138
|
+
"div",
|
|
139
|
+
{},
|
|
140
|
+
h("span", { class: `tag lvl-${record.level}` }, record.level),
|
|
141
|
+
" ",
|
|
142
|
+
record.message,
|
|
143
|
+
properties,
|
|
144
|
+
...origin,
|
|
145
|
+
),
|
|
146
|
+
];
|
|
147
|
+
case "exception":
|
|
148
|
+
return [
|
|
149
|
+
h(
|
|
150
|
+
"div",
|
|
151
|
+
{},
|
|
152
|
+
h("b", { class: "err" }, record.name ?? `error ${record.code}`),
|
|
153
|
+
" · ",
|
|
154
|
+
record.handled
|
|
155
|
+
? h("span", { class: "dim" }, "handled")
|
|
156
|
+
: h("b", { class: "err" }, "unhandled"),
|
|
157
|
+
record.function
|
|
158
|
+
? h("span", { class: "mono" }, ` · ${record.function}`)
|
|
159
|
+
: "",
|
|
160
|
+
record.instance
|
|
161
|
+
? h("span", {}, " on ", pathLink(record.instance))
|
|
162
|
+
: "",
|
|
163
|
+
properties,
|
|
164
|
+
...origin,
|
|
165
|
+
),
|
|
166
|
+
];
|
|
167
|
+
}
|
|
142
168
|
};
|
|
143
169
|
|
|
144
170
|
const byWhom = (entry: { user?: string; host?: string }) =>
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
171
|
+
entry.user || entry.host
|
|
172
|
+
? h(
|
|
173
|
+
"span",
|
|
174
|
+
{ class: "dim" },
|
|
175
|
+
` by ${entry.user ?? "unknown user"}${entry.host ? ` on ${entry.host}` : ""}`,
|
|
176
|
+
)
|
|
177
|
+
: "";
|
|
152
178
|
|
|
153
179
|
const entryBody = (store: Store, entry: TimelineEntry) => {
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
180
|
+
switch (entry.kind) {
|
|
181
|
+
case "app":
|
|
182
|
+
return appBody(store, entry.task, entry.record);
|
|
183
|
+
case "trace":
|
|
184
|
+
return traceBody(store, entry.trace);
|
|
185
|
+
case "request": {
|
|
186
|
+
const { request } = entry;
|
|
187
|
+
return [
|
|
188
|
+
h(
|
|
189
|
+
"div",
|
|
190
|
+
{},
|
|
191
|
+
h("b", { class: "mono" }, request.service),
|
|
192
|
+
" ",
|
|
193
|
+
requestStatus(request),
|
|
194
|
+
request.durationMs === undefined
|
|
195
|
+
? ""
|
|
196
|
+
: ` in ${formatDuration(request.durationMs)}`,
|
|
197
|
+
request.job === undefined
|
|
198
|
+
? ""
|
|
199
|
+
: h(
|
|
200
|
+
"span",
|
|
201
|
+
{},
|
|
202
|
+
" · from ",
|
|
203
|
+
requestJobLink(store, request.job, request.sequence),
|
|
204
|
+
),
|
|
205
|
+
request.error ? h("div", { class: "err" }, request.error) : "",
|
|
206
|
+
),
|
|
207
|
+
];
|
|
208
|
+
}
|
|
209
|
+
case "deploy":
|
|
210
|
+
return [
|
|
211
|
+
h(
|
|
212
|
+
"div",
|
|
213
|
+
{},
|
|
214
|
+
`Release ${entry.release} · ${entry.operation}`,
|
|
215
|
+
entry.build
|
|
216
|
+
? h("span", { class: "mono dim" }, ` build ${entry.build}`)
|
|
217
|
+
: "",
|
|
218
|
+
byWhom(entry),
|
|
219
|
+
),
|
|
220
|
+
];
|
|
221
|
+
case "audit":
|
|
222
|
+
return [
|
|
223
|
+
h(
|
|
224
|
+
"div",
|
|
225
|
+
{},
|
|
226
|
+
h("b", { class: "mono" }, `tsplc ${entry.command}`),
|
|
227
|
+
byWhom(entry),
|
|
228
|
+
entry.error ? h("span", { class: "err" }, ` · ${entry.error}`) : "",
|
|
229
|
+
),
|
|
230
|
+
h(
|
|
231
|
+
"div",
|
|
232
|
+
{ class: "chips" },
|
|
233
|
+
...Object.entries(entry.values).map(([path, value]) =>
|
|
234
|
+
h(
|
|
235
|
+
"span",
|
|
236
|
+
{ class: "chip" },
|
|
237
|
+
pathLink(path),
|
|
238
|
+
value === "" ? " unforced" : ` = ${value}`,
|
|
239
|
+
entry.previous?.[path] === undefined
|
|
240
|
+
? ""
|
|
241
|
+
: h("span", { class: "dim" }, ` (was ${entry.previous[path]})`),
|
|
242
|
+
),
|
|
243
|
+
),
|
|
244
|
+
),
|
|
245
|
+
];
|
|
246
|
+
case "connection":
|
|
247
|
+
return [
|
|
248
|
+
h(
|
|
249
|
+
"div",
|
|
250
|
+
{},
|
|
251
|
+
`Reading values: ${entry.state}`,
|
|
252
|
+
entry.error ? h("span", { class: "err" }, ` · ${entry.error}`) : "",
|
|
253
|
+
),
|
|
254
|
+
];
|
|
255
|
+
}
|
|
221
256
|
};
|
|
222
257
|
|
|
223
258
|
export const recentEntry = (store: Store, entry: TimelineEntry) =>
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
259
|
+
h(
|
|
260
|
+
"div",
|
|
261
|
+
{ class: `entry k-${kindOf(entry)}` },
|
|
262
|
+
h(
|
|
263
|
+
"span",
|
|
264
|
+
{ class: "when mono" },
|
|
265
|
+
formatClock(entry.at),
|
|
266
|
+
entry.approximate
|
|
267
|
+
? h(
|
|
268
|
+
"span",
|
|
269
|
+
{
|
|
270
|
+
class: "approx",
|
|
271
|
+
title:
|
|
272
|
+
"Placed through another clock, so its order against other sources is approximate",
|
|
273
|
+
},
|
|
274
|
+
"≈",
|
|
275
|
+
)
|
|
276
|
+
: "",
|
|
277
|
+
),
|
|
278
|
+
h("span", { class: `source src-${entry.source}` }, entry.source),
|
|
279
|
+
h("div", { class: "body" }, ...entryBody(store, entry)),
|
|
280
|
+
);
|
|
246
281
|
|
|
247
282
|
const clockNote = (store: Store) => {
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
283
|
+
const clock = store.session.clock;
|
|
284
|
+
return `PLC records are placed on the app server's clock from their age when it received them${
|
|
285
|
+
clock ? `, within ±${clock.uncertaintyMs.toFixed(1)} ms` : ""
|
|
286
|
+
}, so their order against other sources is approximate (≈).`;
|
|
252
287
|
};
|
|
253
288
|
|
|
254
289
|
export const recentView = (store: Store): View => {
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
290
|
+
let shown = PAGE;
|
|
291
|
+
let renderTimer: ReturnType<typeof setTimeout> | undefined;
|
|
292
|
+
const list = h("div", { class: "entries" });
|
|
293
|
+
const more = h(
|
|
294
|
+
"button",
|
|
295
|
+
{
|
|
296
|
+
onclick: () => {
|
|
297
|
+
shown += PAGE;
|
|
298
|
+
render();
|
|
299
|
+
},
|
|
300
|
+
},
|
|
301
|
+
`Show ${PAGE} older`,
|
|
302
|
+
);
|
|
303
|
+
const note = h("p", { class: "hint" });
|
|
260
304
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
305
|
+
const toggles = <T extends string>(values: T[], hidden: Set<T>) =>
|
|
306
|
+
values.map((value) => {
|
|
307
|
+
const input = h("input", {
|
|
308
|
+
type: "checkbox",
|
|
309
|
+
checked: !hidden.has(value),
|
|
310
|
+
});
|
|
311
|
+
input.addEventListener("change", () => {
|
|
312
|
+
if (input.checked) {
|
|
313
|
+
hidden.delete(value);
|
|
314
|
+
} else {
|
|
315
|
+
hidden.add(value);
|
|
316
|
+
}
|
|
317
|
+
render();
|
|
318
|
+
});
|
|
319
|
+
return h("label", { class: "check" }, input, value);
|
|
320
|
+
});
|
|
271
321
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
322
|
+
const render = () => {
|
|
323
|
+
clearTimeout(renderTimer);
|
|
324
|
+
renderTimer = undefined;
|
|
325
|
+
note.textContent = clockNote(store);
|
|
326
|
+
const visible = store.timeline.filter(
|
|
327
|
+
(entry) =>
|
|
328
|
+
!hiddenSources.has(entry.source) && !hiddenKinds.has(kindOf(entry)),
|
|
329
|
+
);
|
|
330
|
+
list.replaceChildren(
|
|
331
|
+
...(visible.length
|
|
332
|
+
? visible
|
|
333
|
+
.slice(-shown)
|
|
334
|
+
.reverse()
|
|
335
|
+
.map((entry) => recentEntry(store, entry))
|
|
336
|
+
: [empty("Nothing in the recent window matches these filters.")]),
|
|
337
|
+
);
|
|
338
|
+
more.hidden = visible.length <= shown;
|
|
339
|
+
};
|
|
289
340
|
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
341
|
+
render();
|
|
342
|
+
store.show();
|
|
343
|
+
return {
|
|
344
|
+
element: h(
|
|
345
|
+
"div",
|
|
346
|
+
{ class: "page recent" },
|
|
347
|
+
h("h1", {}, "Recent"),
|
|
348
|
+
h(
|
|
349
|
+
"p",
|
|
350
|
+
{ class: "hint" },
|
|
351
|
+
"The app server's recent window: what the program reported, its traced writes when the trace is on, and the requests it made, with the agent's deployments and audited commands. History lives in the app's telemetry sink, such as PostHog.",
|
|
352
|
+
),
|
|
353
|
+
h(
|
|
354
|
+
"div",
|
|
355
|
+
{ class: "toolbar" },
|
|
356
|
+
h("span", { class: "dim" }, "Source"),
|
|
357
|
+
...toggles(SOURCES, hiddenSources),
|
|
358
|
+
h("span", { class: "dim sep" }, "Kind"),
|
|
359
|
+
...toggles(KINDS, hiddenKinds),
|
|
360
|
+
),
|
|
361
|
+
note,
|
|
362
|
+
list,
|
|
363
|
+
more,
|
|
364
|
+
),
|
|
365
|
+
update(topics) {
|
|
366
|
+
if (!topics.has("timeline") && !topics.has("session")) {
|
|
367
|
+
return;
|
|
368
|
+
}
|
|
369
|
+
renderTimer ??= setTimeout(render, RENDER_INTERVAL_MS);
|
|
370
|
+
},
|
|
371
|
+
dispose() {
|
|
372
|
+
clearTimeout(renderTimer);
|
|
373
|
+
},
|
|
374
|
+
};
|
|
322
375
|
};
|