@kwirthmagnify/kwirth-plugin-provider-debug 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/front.js +128 -9
- package/package.json +1 -1
package/front.js
CHANGED
|
@@ -232,6 +232,27 @@
|
|
|
232
232
|
if (token === "true" || token === "false" || token === "null") return theme.palette.secondary.main;
|
|
233
233
|
return theme.palette.warning.main;
|
|
234
234
|
};
|
|
235
|
+
const paint = (text, color, keyBase) => {
|
|
236
|
+
const needle = (props.highlight ?? "").trim();
|
|
237
|
+
if (needle === "") return [/* @__PURE__ */ import_react2.default.createElement("span", { key: keyBase, style: color ? { color } : void 0 }, text)];
|
|
238
|
+
const nodes = [];
|
|
239
|
+
const lower = text.toLowerCase();
|
|
240
|
+
const target = needle.toLowerCase();
|
|
241
|
+
let from = 0;
|
|
242
|
+
let at = lower.indexOf(target);
|
|
243
|
+
while (at >= 0) {
|
|
244
|
+
if (at > from) nodes.push(/* @__PURE__ */ import_react2.default.createElement("span", { key: `${keyBase}-${from}`, style: color ? { color } : void 0 }, text.slice(from, at)));
|
|
245
|
+
nodes.push(
|
|
246
|
+
// el marcador permite que el buscador centre la COINCIDENCIA y no la tarjeta: con un
|
|
247
|
+
// JSON de miles de líneas, centrar la tarjeta deja el resultado fuera de pantalla
|
|
248
|
+
/* @__PURE__ */ import_react2.default.createElement("span", { key: `${keyBase}-h${at}`, "data-pd-hit": "1", style: { backgroundColor: theme.palette.text.primary, color: theme.palette.background.paper } }, text.slice(at, at + needle.length))
|
|
249
|
+
);
|
|
250
|
+
from = at + needle.length;
|
|
251
|
+
at = lower.indexOf(target, from);
|
|
252
|
+
}
|
|
253
|
+
if (from < text.length) nodes.push(/* @__PURE__ */ import_react2.default.createElement("span", { key: `${keyBase}-${from}`, style: color ? { color } : void 0 }, text.slice(from)));
|
|
254
|
+
return nodes;
|
|
255
|
+
};
|
|
235
256
|
const render = () => {
|
|
236
257
|
let text;
|
|
237
258
|
try {
|
|
@@ -244,11 +265,11 @@
|
|
|
244
265
|
let match;
|
|
245
266
|
TOKEN.lastIndex = 0;
|
|
246
267
|
while ((match = TOKEN.exec(text)) !== null) {
|
|
247
|
-
if (match.index > last) nodes.push(
|
|
248
|
-
nodes.push(
|
|
268
|
+
if (match.index > last) nodes.push(...paint(text.slice(last, match.index), void 0, `p${last}`));
|
|
269
|
+
nodes.push(...paint(match[0], colorOf(match[0]), `t${match.index}`));
|
|
249
270
|
last = match.index + match[0].length;
|
|
250
271
|
}
|
|
251
|
-
if (last < text.length) nodes.push(
|
|
272
|
+
if (last < text.length) nodes.push(...paint(text.slice(last), void 0, `p${last}`));
|
|
252
273
|
return nodes;
|
|
253
274
|
};
|
|
254
275
|
return /* @__PURE__ */ import_react2.default.createElement(import_material2.Box, { component: "pre", sx: { m: 0, fontFamily: "monospace", fontSize: "0.75rem", whiteSpace: "pre-wrap", wordBreak: "break-all", overflowX: "auto" } }, render());
|
|
@@ -263,14 +284,56 @@
|
|
|
263
284
|
const [boxTop, setBoxTop] = (0, import_react3.useState)(0);
|
|
264
285
|
const [, forceRender] = (0, import_react3.useState)(0);
|
|
265
286
|
const [copied, setCopied] = (0, import_react3.useState)(null);
|
|
287
|
+
const [search, setSearch] = (0, import_react3.useState)("");
|
|
288
|
+
const [matchPos, setMatchPos] = (0, import_react3.useState)(-1);
|
|
289
|
+
const [expanded, setExpanded] = (0, import_react3.useState)(/* @__PURE__ */ new Set());
|
|
290
|
+
const cardRefs = (0, import_react3.useRef)(/* @__PURE__ */ new Map());
|
|
291
|
+
const searchText = (0, import_react3.useRef)(/* @__PURE__ */ new WeakMap());
|
|
266
292
|
(0, import_react3.useEffect)(() => {
|
|
267
293
|
if (boxRef.current) setBoxTop(boxRef.current.getBoundingClientRect().top);
|
|
268
294
|
});
|
|
269
295
|
const clear = () => {
|
|
270
296
|
data.events = [];
|
|
271
297
|
data.signals = [];
|
|
298
|
+
setExpanded(/* @__PURE__ */ new Set());
|
|
299
|
+
cardRefs.current.clear();
|
|
300
|
+
setMatchPos(-1);
|
|
272
301
|
forceRender((n) => n + 1);
|
|
273
302
|
};
|
|
303
|
+
const textOf = (event) => {
|
|
304
|
+
const cached = searchText.current.get(event);
|
|
305
|
+
if (cached !== void 0) return cached;
|
|
306
|
+
let text;
|
|
307
|
+
try {
|
|
308
|
+
text = (event.providerId + " " + JSON.stringify(event.event)).toLowerCase();
|
|
309
|
+
} catch {
|
|
310
|
+
text = event.providerId.toLowerCase();
|
|
311
|
+
}
|
|
312
|
+
searchText.current.set(event, text);
|
|
313
|
+
return text;
|
|
314
|
+
};
|
|
315
|
+
const matches = () => {
|
|
316
|
+
const needle = search.trim().toLowerCase();
|
|
317
|
+
if (needle === "") return [];
|
|
318
|
+
return data.events.filter((event) => textOf(event).includes(needle));
|
|
319
|
+
};
|
|
320
|
+
const isMatch = (event) => {
|
|
321
|
+
const needle = search.trim().toLowerCase();
|
|
322
|
+
return needle !== "" && textOf(event).includes(needle);
|
|
323
|
+
};
|
|
324
|
+
const goToMatch = (pos) => {
|
|
325
|
+
const found2 = matches();
|
|
326
|
+
if (found2.length === 0) return;
|
|
327
|
+
const next = (pos % found2.length + found2.length) % found2.length;
|
|
328
|
+
const target = found2[next];
|
|
329
|
+
setMatchPos(next);
|
|
330
|
+
setExpanded((prev) => new Set(prev).add(target));
|
|
331
|
+
setTimeout(() => {
|
|
332
|
+
const card = cardRefs.current.get(target);
|
|
333
|
+
const hit = card?.querySelector("[data-pd-hit]");
|
|
334
|
+
(hit ?? card)?.scrollIntoView({ block: "center" });
|
|
335
|
+
}, 0);
|
|
336
|
+
};
|
|
274
337
|
const writeClipboard = async (text) => {
|
|
275
338
|
try {
|
|
276
339
|
await navigator.clipboard.writeText(text);
|
|
@@ -295,7 +358,7 @@
|
|
|
295
358
|
writeClipboard(JSON.stringify(event.event, null, 2)).then((ok) => {
|
|
296
359
|
if (!ok) return;
|
|
297
360
|
setCopied(event);
|
|
298
|
-
setTimeout(() => setCopied((
|
|
361
|
+
setTimeout(() => setCopied((current2) => current2 === event ? null : current2), 1500);
|
|
299
362
|
});
|
|
300
363
|
};
|
|
301
364
|
const summaryOf = (event) => {
|
|
@@ -311,14 +374,70 @@
|
|
|
311
374
|
if (data.providers.length === 0) return /* @__PURE__ */ import_react3.default.createElement(import_material3.Typography, { variant: "body2", color: "text.secondary" }, "No providers running.");
|
|
312
375
|
return /* @__PURE__ */ import_react3.default.createElement(import_material3.Stack, { direction: "row", spacing: 1, flexWrap: "wrap", useFlexGap: true }, data.providers.map((p) => /* @__PURE__ */ import_react3.default.createElement(import_material3.Chip, { key: p.id, label: p.id, size: "small", variant: p.id === instanceConfig.providerId ? "filled" : "outlined" })));
|
|
313
376
|
};
|
|
314
|
-
const
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
377
|
+
const toggle = (event) => setExpanded((prev) => {
|
|
378
|
+
const next = new Set(prev);
|
|
379
|
+
if (next.has(event)) next.delete(event);
|
|
380
|
+
else next.add(event);
|
|
381
|
+
return next;
|
|
382
|
+
});
|
|
383
|
+
const formatEvent = (event, index, current2) => {
|
|
384
|
+
const open = expanded.has(event);
|
|
385
|
+
return /* @__PURE__ */ import_react3.default.createElement(
|
|
386
|
+
import_material3.Paper,
|
|
387
|
+
{
|
|
388
|
+
key: index,
|
|
389
|
+
variant: "outlined",
|
|
390
|
+
ref: (el) => {
|
|
391
|
+
if (el) cardRefs.current.set(event, el);
|
|
392
|
+
else cardRefs.current.delete(event);
|
|
393
|
+
},
|
|
394
|
+
sx: { mb: 0.5, ...current2 === event ? { outline: 2, outlineColor: "warning.main", outlineOffset: -2 } : {} }
|
|
395
|
+
},
|
|
396
|
+
/* @__PURE__ */ import_react3.default.createElement(import_material3.Stack, { direction: "row", spacing: 1.5, alignItems: "center", sx: { minWidth: 0, px: 1, py: 0.5, cursor: "pointer" }, onClick: () => toggle(event) }, /* @__PURE__ */ import_react3.default.createElement(import_material3.IconButton, { size: "small", "aria-label": open ? "Collapse event" : "Expand event", onClick: (e) => {
|
|
397
|
+
e.stopPropagation();
|
|
398
|
+
toggle(event);
|
|
399
|
+
} }, open ? /* @__PURE__ */ import_react3.default.createElement(import_icons_material2.ExpandLess, { fontSize: "small" }) : /* @__PURE__ */ import_react3.default.createElement(import_icons_material2.ExpandMore, { fontSize: "small" })), /* @__PURE__ */ import_react3.default.createElement(import_material3.Typography, { variant: "caption", color: isMatch(event) ? "warning.main" : "text.secondary", sx: { fontFamily: "monospace" } }, new Date(event.ts).toISOString()), /* @__PURE__ */ import_react3.default.createElement(import_material3.Chip, { label: event.providerId, size: "small", variant: "outlined", sx: { fontSize: "0.65rem", height: 18 } }), /* @__PURE__ */ import_react3.default.createElement(import_material3.Typography, { variant: "caption", color: "text.secondary", noWrap: true }, summaryOf(event.event)), /* @__PURE__ */ import_react3.default.createElement(import_material3.Tooltip, { title: copied === event ? "Copied" : "Copy event JSON" }, /* @__PURE__ */ import_react3.default.createElement(import_material3.IconButton, { size: "small", "aria-label": "Copy event JSON", sx: { ml: "auto" }, onClick: (e) => {
|
|
400
|
+
e.stopPropagation();
|
|
401
|
+
copy(event);
|
|
402
|
+
} }, copied === event ? /* @__PURE__ */ import_react3.default.createElement(import_icons_material2.Check, { fontSize: "small", color: "success" }) : /* @__PURE__ */ import_react3.default.createElement(import_icons_material2.ContentCopy, { fontSize: "small" })))),
|
|
403
|
+
open && /* @__PURE__ */ import_react3.default.createElement(import_material3.Box, { sx: { px: 2, pb: 1 } }, /* @__PURE__ */ import_react3.default.createElement(JsonBlock, { value: event.event, highlight: search }))
|
|
404
|
+
);
|
|
405
|
+
};
|
|
318
406
|
if (!data.started) {
|
|
319
407
|
return /* @__PURE__ */ import_react3.default.createElement(import_material3.Box, { sx: { p: 2 } }, /* @__PURE__ */ import_react3.default.createElement(import_material3.Typography, { color: "text.secondary" }, "Provider Debug not started. Start the channel (tab settings \u2699 \u2192 Start) to subscribe to a provider and watch its raw events."));
|
|
320
408
|
}
|
|
321
|
-
|
|
409
|
+
const found = matches();
|
|
410
|
+
const current = matchPos >= 0 && matchPos < found.length ? found[matchPos] : void 0;
|
|
411
|
+
return /* @__PURE__ */ import_react3.default.createElement(import_material3.Card, { sx: { flex: 1, width: "98%", alignSelf: "center", m: 1 } }, /* @__PURE__ */ import_react3.default.createElement(import_material3.CardHeader, { title: /* @__PURE__ */ import_react3.default.createElement(import_material3.Stack, { direction: "row", alignItems: "center", sx: { width: "100%" } }, /* @__PURE__ */ import_react3.default.createElement(import_material3.Typography, { mr: 4 }, /* @__PURE__ */ import_react3.default.createElement("b", null, "Provider:"), " ", instanceConfig.providerId || "(none)"), /* @__PURE__ */ import_react3.default.createElement(import_material3.Typography, { mr: 4 }, /* @__PURE__ */ import_react3.default.createElement("b", null, "Events:"), " ", data.events.length, " / ", config.maxEvents), /* @__PURE__ */ import_react3.default.createElement(import_material3.Typography, { mr: 4 }, /* @__PURE__ */ import_react3.default.createElement(import_icons_material2.Info, { fontSize: "small", sx: { mb: 0.25 } }), /* @__PURE__ */ import_react3.default.createElement("b", null, "\xA0Status:"), " ", data.paused ? "paused" : data.started ? "started" : "stopped"), /* @__PURE__ */ import_react3.default.createElement(import_material3.Stack, { direction: "row", alignItems: "center", spacing: 0.5, sx: { ml: "auto" } }, /* @__PURE__ */ import_react3.default.createElement(import_material3.Typography, { variant: "caption", color: found.length === 0 && search.trim() !== "" ? "warning.main" : "text.secondary", sx: { minWidth: 44, textAlign: "right" } }, `${matchPos + 1}/${found.length}`), /* @__PURE__ */ import_react3.default.createElement(
|
|
412
|
+
import_material3.TextField,
|
|
413
|
+
{
|
|
414
|
+
value: search,
|
|
415
|
+
onChange: (e) => {
|
|
416
|
+
setSearch(e.target.value);
|
|
417
|
+
setMatchPos(-1);
|
|
418
|
+
},
|
|
419
|
+
onKeyDown: (e) => {
|
|
420
|
+
if (e.key !== "Enter") return;
|
|
421
|
+
e.preventDefault();
|
|
422
|
+
goToMatch(e.shiftKey ? matchPos - 1 : matchPos + 1);
|
|
423
|
+
},
|
|
424
|
+
placeholder: "Search events",
|
|
425
|
+
variant: "standard",
|
|
426
|
+
sx: { width: 200 },
|
|
427
|
+
slotProps: {
|
|
428
|
+
htmlInput: { "aria-label": "Search events" },
|
|
429
|
+
input: {
|
|
430
|
+
startAdornment: /* @__PURE__ */ import_react3.default.createElement(import_material3.InputAdornment, { position: "start" }, /* @__PURE__ */ import_react3.default.createElement(import_icons_material2.Search, { fontSize: "small" })),
|
|
431
|
+
// siempre presente y deshabilitado: si se renderiza en
|
|
432
|
+
// condicional desaparece bajo el propio click que lo pulsa
|
|
433
|
+
endAdornment: /* @__PURE__ */ import_react3.default.createElement(import_material3.InputAdornment, { position: "end" }, /* @__PURE__ */ import_react3.default.createElement(import_material3.IconButton, { size: "small", "aria-label": "Clear search", disabled: search === "", onClick: () => {
|
|
434
|
+
setSearch("");
|
|
435
|
+
setMatchPos(-1);
|
|
436
|
+
} }, /* @__PURE__ */ import_react3.default.createElement(import_icons_material2.Clear, { fontSize: "small" })))
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
), /* @__PURE__ */ import_react3.default.createElement(import_material3.Tooltip, { title: "Previous match (Shift+Enter)" }, /* @__PURE__ */ import_react3.default.createElement("span", null, /* @__PURE__ */ import_react3.default.createElement(import_material3.IconButton, { size: "small", "aria-label": "Previous match", disabled: found.length === 0, onClick: () => goToMatch(matchPos - 1) }, /* @__PURE__ */ import_react3.default.createElement(import_icons_material2.ArrowUpward, { fontSize: "small" })))), /* @__PURE__ */ import_react3.default.createElement(import_material3.Tooltip, { title: "Next match (Enter)" }, /* @__PURE__ */ import_react3.default.createElement("span", null, /* @__PURE__ */ import_react3.default.createElement(import_material3.IconButton, { size: "small", "aria-label": "Next match", disabled: found.length === 0, onClick: () => goToMatch(matchPos + 1) }, /* @__PURE__ */ import_react3.default.createElement(import_icons_material2.ArrowDownward, { fontSize: "small" })))), /* @__PURE__ */ import_react3.default.createElement(import_material3.Tooltip, { title: "Clear captured events" }, /* @__PURE__ */ import_react3.default.createElement("span", null, /* @__PURE__ */ import_react3.default.createElement(import_material3.IconButton, { size: "small", "aria-label": "Clear captured events", onClick: clear, disabled: data.events.length === 0 && data.signals.length === 0 }, /* @__PURE__ */ import_react3.default.createElement(import_icons_material2.DeleteSweep, { fontSize: "small" })))))) }), /* @__PURE__ */ import_react3.default.createElement(import_material3.CardContent, null, /* @__PURE__ */ import_react3.default.createElement(import_material3.Stack, { direction: "column", spacing: 1, sx: { mb: 1 } }, /* @__PURE__ */ import_react3.default.createElement(import_material3.Stack, { direction: "row", spacing: 1, alignItems: "center", flexWrap: "wrap", useFlexGap: true }, /* @__PURE__ */ import_react3.default.createElement(import_material3.Typography, { variant: "caption", color: "text.secondary" }, "Running providers"), formatProviders()), data.signals.map((s, index) => /* @__PURE__ */ import_react3.default.createElement(import_material3.Typography, { key: index, variant: "caption", color: "text.secondary" }, "*** ", s, " ***"))), /* @__PURE__ */ import_react3.default.createElement(import_material3.Box, { ref: boxRef, sx: { display: "flex", flexDirection: "column", overflowY: "auto", overflowX: "hidden", width: "100%", flexGrow: 1, height: `calc(100vh - ${boxTop}px - 35px)` } }, /* @__PURE__ */ import_react3.default.createElement(import_material3.Box, { sx: { flex: 1, overflowY: "auto", ml: 1, mr: 1 } }, data.events.map((e, index) => formatEvent(e, index, current))))));
|
|
322
441
|
};
|
|
323
442
|
|
|
324
443
|
// src/front/ProviderDebugChannel.ts
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"id": "provider-debug",
|
|
5
5
|
"name": "@kwirthmagnify/kwirth-plugin-provider-debug",
|
|
6
6
|
"displayName": "Provider Debug",
|
|
7
|
-
"version": "0.1.
|
|
7
|
+
"version": "0.1.1",
|
|
8
8
|
"description": "Provider debugging channel for Kwirth - subscribes to a running provider and streams its raw events",
|
|
9
9
|
"icon": "DataObjectOutlined",
|
|
10
10
|
"requiresRestart": false,
|