@mugenlabs/logtape-devtools 0.2.1 → 0.4.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/README.md +193 -20
- package/assets/panel.png +0 -0
- package/dist/chunk-FDWUISCJ.mjs +300 -0
- package/dist/chunk-FDWUISCJ.mjs.map +1 -0
- package/dist/index.d.ts +36 -74
- package/dist/index.mjs +408 -547
- package/dist/index.mjs.map +1 -1
- package/dist/sink.d.ts +140 -0
- package/dist/sink.mjs +13 -0
- package/dist/sink.mjs.map +1 -0
- package/package.json +47 -26
package/dist/index.mjs
CHANGED
|
@@ -1,110 +1,93 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
listener();
|
|
9
|
-
}
|
|
10
|
-
}
|
|
11
|
-
return {
|
|
12
|
-
getSnapshot: () => records,
|
|
13
|
-
addRecord: (record) => {
|
|
14
|
-
records = [...records, record];
|
|
15
|
-
if (records.length > max) {
|
|
16
|
-
records = records.slice(records.length - max);
|
|
17
|
-
}
|
|
18
|
-
notify();
|
|
19
|
-
},
|
|
20
|
-
clear: () => {
|
|
21
|
-
records = [];
|
|
22
|
-
notify();
|
|
23
|
-
},
|
|
24
|
-
subscribe: (listener) => {
|
|
25
|
-
listeners.add(listener);
|
|
26
|
-
return () => {
|
|
27
|
-
listeners.delete(listener);
|
|
28
|
-
};
|
|
29
|
-
},
|
|
30
|
-
setMaxSize: (size) => {
|
|
31
|
-
max = size;
|
|
32
|
-
if (records.length > max) {
|
|
33
|
-
records = records.slice(records.length - max);
|
|
34
|
-
notify();
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
var defaultLogStore = createLogStore();
|
|
1
|
+
import {
|
|
2
|
+
LOG_LEVELS,
|
|
3
|
+
createDevtoolsSink,
|
|
4
|
+
createLogStore,
|
|
5
|
+
defaultLogStore,
|
|
6
|
+
safeStringify
|
|
7
|
+
} from "./chunk-FDWUISCJ.mjs";
|
|
40
8
|
|
|
41
9
|
// src/plugin/logtape-devtools-plugin.tsx
|
|
42
|
-
import { useCallback as
|
|
10
|
+
import { useCallback as useCallback4, useMemo as useMemo2, useState as useState2, useSyncExternalStore } from "react";
|
|
43
11
|
|
|
44
12
|
// src/plugin/components/log-list.tsx
|
|
45
|
-
import {
|
|
13
|
+
import { useVirtualizer } from "@tanstack/react-virtual";
|
|
14
|
+
import { useCallback as useCallback2, useEffect, useRef } from "react";
|
|
46
15
|
|
|
47
16
|
// src/plugin/theme.ts
|
|
48
17
|
var theme = {
|
|
49
18
|
colors: {
|
|
19
|
+
accent: "#6366f1",
|
|
20
|
+
accentHover: "#818cf8",
|
|
50
21
|
background: "#1e1e1e",
|
|
51
|
-
surface: "#1a1a1a",
|
|
52
|
-
surfaceHover: "#2a2a2a",
|
|
53
|
-
surfaceSelected: "#2a2a3a",
|
|
54
22
|
border: "#333",
|
|
55
|
-
borderInput: "#444",
|
|
56
23
|
borderFocus: "#6366f1",
|
|
57
|
-
|
|
58
|
-
textSecondary: "#888",
|
|
59
|
-
textMuted: "#666",
|
|
60
|
-
textDimmed: "#555",
|
|
61
|
-
white: "#fff",
|
|
62
|
-
accent: "#6366f1",
|
|
63
|
-
accentHover: "#818cf8",
|
|
24
|
+
borderInput: "#444",
|
|
64
25
|
levels: {
|
|
65
|
-
|
|
66
|
-
debug: {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
26
|
+
// Badge colours keep at least 4.5:1 contrast against white badge text.
|
|
27
|
+
debug: { badge: "#2f7a2f", bg: "#1a2a1a", color: "#88bb88" },
|
|
28
|
+
error: { badge: "#dc2626", bg: "#2a1a1a", color: "#ef4444" },
|
|
29
|
+
fatal: { badge: "#b91c1c", bg: "#3a0a0a", color: "#ff6b6b" },
|
|
30
|
+
info: { badge: "#2563eb", bg: "#1a2a3a", color: "#60a5fa" },
|
|
31
|
+
trace: { badge: "#5555aa", bg: "#1a1a2e", color: "#8888bb" },
|
|
32
|
+
warning: { badge: "#eab308", bg: "#2a2a1a", color: "#facc15" }
|
|
71
33
|
},
|
|
72
34
|
scrollbar: "#444",
|
|
73
|
-
scrollbarHover: "#555"
|
|
35
|
+
scrollbarHover: "#555",
|
|
36
|
+
surface: "#1a1a1a",
|
|
37
|
+
surfaceHover: "#2a2a2a",
|
|
38
|
+
surfaceSelected: "#2a2a3a",
|
|
39
|
+
textDimmed: "#555",
|
|
40
|
+
textMuted: "#666",
|
|
41
|
+
textPrimary: "#e0e0e0",
|
|
42
|
+
textSecondary: "#888",
|
|
43
|
+
white: "#fff"
|
|
74
44
|
},
|
|
75
45
|
fontFamily: {
|
|
76
46
|
mono: 'ui-monospace, "Cascadia Code", "Source Code Pro", Menlo, Consolas, monospace',
|
|
77
47
|
sans: 'system-ui, -apple-system, "Segoe UI", Roboto, sans-serif'
|
|
78
48
|
},
|
|
79
49
|
fontSize: {
|
|
80
|
-
xs: "9px",
|
|
81
|
-
sm: "10px",
|
|
82
|
-
md: "11px",
|
|
83
50
|
base: "12px",
|
|
84
|
-
lg: "13px"
|
|
51
|
+
lg: "13px",
|
|
52
|
+
md: "11px",
|
|
53
|
+
sm: "10px",
|
|
54
|
+
xs: "9px"
|
|
85
55
|
},
|
|
86
56
|
radius: {
|
|
87
|
-
sm: "3px",
|
|
88
|
-
md: "4px",
|
|
89
57
|
lg: "6px",
|
|
90
|
-
|
|
58
|
+
md: "4px",
|
|
59
|
+
pill: "10px",
|
|
60
|
+
sm: "3px"
|
|
91
61
|
},
|
|
92
62
|
spacing: {
|
|
93
|
-
xs: "2px",
|
|
94
|
-
sm: "4px",
|
|
95
|
-
md: "6px",
|
|
96
63
|
lg: "8px",
|
|
64
|
+
md: "6px",
|
|
65
|
+
sm: "4px",
|
|
97
66
|
xl: "12px",
|
|
67
|
+
xs: "2px",
|
|
98
68
|
xxl: "16px"
|
|
99
69
|
}
|
|
100
70
|
};
|
|
71
|
+
var getLevelColors = (level) => theme.colors.levels[level] ?? theme.colors.levels.info;
|
|
101
72
|
|
|
102
73
|
// src/plugin/components/log-row.tsx
|
|
103
|
-
import { useCallback } from "react";
|
|
74
|
+
import { memo, useCallback } from "react";
|
|
75
|
+
|
|
76
|
+
// src/plugin/format.ts
|
|
77
|
+
var timeFormatter;
|
|
78
|
+
function formatTime(ts) {
|
|
79
|
+
timeFormatter ??= new Intl.DateTimeFormat(void 0, {
|
|
80
|
+
hour: "2-digit",
|
|
81
|
+
hour12: false,
|
|
82
|
+
minute: "2-digit",
|
|
83
|
+
second: "2-digit"
|
|
84
|
+
});
|
|
85
|
+
return timeFormatter.format(new Date(ts));
|
|
86
|
+
}
|
|
104
87
|
|
|
105
88
|
// src/plugin/icons.tsx
|
|
106
89
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
107
|
-
var defaults = {
|
|
90
|
+
var defaults = { color: "currentColor", size: 14 };
|
|
108
91
|
var Svg = ({
|
|
109
92
|
size = defaults.size,
|
|
110
93
|
color = defaults.color,
|
|
@@ -159,15 +142,16 @@ var Trash2Icon = (props) => /* @__PURE__ */ jsxs(Svg, { ...props, children: [
|
|
|
159
142
|
// src/plugin/components/level-badge.tsx
|
|
160
143
|
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
161
144
|
var LEVEL_LABELS = {
|
|
162
|
-
trace: "TRC",
|
|
163
145
|
debug: "DBG",
|
|
164
|
-
info: "INF",
|
|
165
|
-
warning: "WRN",
|
|
166
146
|
error: "ERR",
|
|
167
|
-
fatal: "FTL"
|
|
147
|
+
fatal: "FTL",
|
|
148
|
+
info: "INF",
|
|
149
|
+
trace: "TRC",
|
|
150
|
+
warning: "WRN"
|
|
168
151
|
};
|
|
169
152
|
var LevelBadge = ({ level }) => {
|
|
170
|
-
const colors =
|
|
153
|
+
const colors = getLevelColors(level);
|
|
154
|
+
const label = LEVEL_LABELS[level] ?? level.toUpperCase();
|
|
171
155
|
return /* @__PURE__ */ jsx2(
|
|
172
156
|
"span",
|
|
173
157
|
{
|
|
@@ -185,100 +169,129 @@ var LevelBadge = ({ level }) => {
|
|
|
185
169
|
textAlign: "center",
|
|
186
170
|
textTransform: "uppercase"
|
|
187
171
|
},
|
|
188
|
-
children:
|
|
172
|
+
children: label
|
|
189
173
|
}
|
|
190
174
|
);
|
|
191
175
|
};
|
|
192
176
|
|
|
193
177
|
// src/plugin/components/log-detail.tsx
|
|
194
178
|
import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
}
|
|
211
|
-
var
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
179
|
+
var detailRowStyle = {
|
|
180
|
+
display: "flex",
|
|
181
|
+
gap: theme.spacing.lg,
|
|
182
|
+
marginBottom: theme.spacing.md
|
|
183
|
+
};
|
|
184
|
+
var detailLabelStyle = {
|
|
185
|
+
color: theme.colors.textMuted,
|
|
186
|
+
flexShrink: 0,
|
|
187
|
+
fontSize: theme.fontSize.md,
|
|
188
|
+
minWidth: "72px",
|
|
189
|
+
textAlign: "right"
|
|
190
|
+
};
|
|
191
|
+
var detailValueStyle = {
|
|
192
|
+
fontSize: theme.fontSize.base,
|
|
193
|
+
wordBreak: "break-all"
|
|
194
|
+
};
|
|
195
|
+
var containerStyle = {
|
|
196
|
+
borderTop: `1px solid ${theme.colors.border}`,
|
|
197
|
+
padding: `${theme.spacing.lg} ${theme.spacing.xl}`
|
|
198
|
+
};
|
|
199
|
+
var categoryStyle = {
|
|
200
|
+
color: theme.colors.accent,
|
|
201
|
+
fontFamily: theme.fontFamily.mono
|
|
202
|
+
};
|
|
203
|
+
var callerStyle = {
|
|
204
|
+
color: theme.colors.textSecondary,
|
|
205
|
+
fontFamily: theme.fontFamily.mono
|
|
206
|
+
};
|
|
207
|
+
var messageStyle = { color: theme.colors.textPrimary };
|
|
208
|
+
var propertiesStyle = {
|
|
209
|
+
background: "rgba(0,0,0,0.3)",
|
|
210
|
+
borderRadius: theme.radius.md,
|
|
211
|
+
color: theme.colors.textPrimary,
|
|
212
|
+
fontFamily: theme.fontFamily.mono,
|
|
213
|
+
fontSize: theme.fontSize.md,
|
|
214
|
+
margin: 0,
|
|
215
|
+
maxHeight: "200px",
|
|
216
|
+
overflow: "auto",
|
|
217
|
+
padding: theme.spacing.lg,
|
|
218
|
+
whiteSpace: "pre-wrap",
|
|
219
|
+
wordBreak: "break-all"
|
|
220
|
+
};
|
|
221
|
+
var DetailRow = ({ label, children }) => /* @__PURE__ */ jsxs2("div", { style: detailRowStyle, children: [
|
|
222
|
+
/* @__PURE__ */ jsx3("span", { style: detailLabelStyle, children: label }),
|
|
223
|
+
/* @__PURE__ */ jsx3("span", { style: detailValueStyle, children })
|
|
226
224
|
] });
|
|
227
225
|
var LogDetail = ({ record }) => {
|
|
228
226
|
const levelColors = theme.colors.levels[record.level];
|
|
229
227
|
const hasProperties = Object.keys(record.properties).length > 0;
|
|
230
|
-
return /* @__PURE__ */ jsxs2(
|
|
231
|
-
"
|
|
232
|
-
{
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
},
|
|
239
|
-
children: [
|
|
240
|
-
/* @__PURE__ */ jsx3(DetailRow, { label: "Time", children: formatTimestamp(record.timestamp) }),
|
|
241
|
-
/* @__PURE__ */ jsx3(DetailRow, { label: "Level", children: /* @__PURE__ */ jsx3("span", { style: { color: levelColors.color, fontWeight: 600 }, children: record.level }) }),
|
|
242
|
-
/* @__PURE__ */ jsx3(DetailRow, { label: "Category", children: /* @__PURE__ */ jsx3("span", { style: { color: theme.colors.accent, fontFamily: theme.fontFamily.mono }, children: record.category.join(".") }) }),
|
|
243
|
-
record.caller && /* @__PURE__ */ jsx3(DetailRow, { label: "Caller", children: /* @__PURE__ */ jsx3("span", { style: { color: theme.colors.textSecondary, fontFamily: theme.fontFamily.mono }, children: record.caller }) }),
|
|
244
|
-
/* @__PURE__ */ jsx3(DetailRow, { label: "Message", children: /* @__PURE__ */ jsx3("span", { style: { color: theme.colors.textPrimary }, children: record.messageText }) }),
|
|
245
|
-
hasProperties && /* @__PURE__ */ jsx3(DetailRow, { label: "Data", children: /* @__PURE__ */ jsx3(
|
|
246
|
-
"pre",
|
|
247
|
-
{
|
|
248
|
-
style: {
|
|
249
|
-
background: "rgba(0,0,0,0.3)",
|
|
250
|
-
borderRadius: theme.radius.md,
|
|
251
|
-
color: theme.colors.textPrimary,
|
|
252
|
-
fontFamily: theme.fontFamily.mono,
|
|
253
|
-
fontSize: theme.fontSize.md,
|
|
254
|
-
margin: 0,
|
|
255
|
-
maxHeight: "200px",
|
|
256
|
-
overflow: "auto",
|
|
257
|
-
padding: theme.spacing.lg,
|
|
258
|
-
whiteSpace: "pre-wrap",
|
|
259
|
-
wordBreak: "break-all"
|
|
260
|
-
},
|
|
261
|
-
children: safeStringify(record.properties)
|
|
262
|
-
}
|
|
263
|
-
) })
|
|
264
|
-
]
|
|
265
|
-
}
|
|
266
|
-
);
|
|
228
|
+
return /* @__PURE__ */ jsxs2("div", { "data-testid": "log-detail", style: { ...containerStyle, background: levelColors.bg }, children: [
|
|
229
|
+
/* @__PURE__ */ jsx3(DetailRow, { label: "Time", children: formatTime(record.timestamp) }),
|
|
230
|
+
/* @__PURE__ */ jsx3(DetailRow, { label: "Level", children: /* @__PURE__ */ jsx3("span", { style: { color: levelColors.color, fontWeight: 600 }, children: record.level }) }),
|
|
231
|
+
/* @__PURE__ */ jsx3(DetailRow, { label: "Category", children: /* @__PURE__ */ jsx3("span", { style: categoryStyle, children: record.category.join(".") }) }),
|
|
232
|
+
record.caller ? /* @__PURE__ */ jsx3(DetailRow, { label: "Caller", children: /* @__PURE__ */ jsx3("span", { style: callerStyle, children: record.caller }) }) : null,
|
|
233
|
+
/* @__PURE__ */ jsx3(DetailRow, { label: "Message", children: /* @__PURE__ */ jsx3("span", { style: messageStyle, children: record.messageText }) }),
|
|
234
|
+
hasProperties && /* @__PURE__ */ jsx3(DetailRow, { label: "Data", children: /* @__PURE__ */ jsx3("pre", { style: propertiesStyle, children: safeStringify(record.properties, 2) }) })
|
|
235
|
+
] });
|
|
267
236
|
};
|
|
268
237
|
|
|
269
238
|
// src/plugin/components/log-row.tsx
|
|
270
239
|
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
240
|
+
var rowStyle = {
|
|
241
|
+
alignItems: "center",
|
|
242
|
+
border: "none",
|
|
243
|
+
borderBottom: `1px solid ${theme.colors.border}`,
|
|
244
|
+
cursor: "pointer",
|
|
245
|
+
display: "flex",
|
|
246
|
+
gap: theme.spacing.lg,
|
|
247
|
+
padding: `${theme.spacing.md} ${theme.spacing.xl}`,
|
|
248
|
+
textAlign: "left",
|
|
249
|
+
transition: "background 0.1s, filter 0.1s",
|
|
250
|
+
width: "100%"
|
|
251
|
+
};
|
|
252
|
+
var timestampStyle = {
|
|
253
|
+
color: theme.colors.textDimmed,
|
|
254
|
+
flexShrink: 0,
|
|
255
|
+
fontFamily: theme.fontFamily.mono,
|
|
256
|
+
fontSize: theme.fontSize.md
|
|
257
|
+
};
|
|
258
|
+
var categoryStyle2 = {
|
|
259
|
+
color: theme.colors.accent,
|
|
260
|
+
flexShrink: 0,
|
|
261
|
+
fontFamily: theme.fontFamily.mono,
|
|
262
|
+
fontSize: theme.fontSize.md,
|
|
263
|
+
maxWidth: "180px",
|
|
264
|
+
overflow: "hidden",
|
|
265
|
+
textOverflow: "ellipsis",
|
|
266
|
+
whiteSpace: "nowrap"
|
|
267
|
+
};
|
|
268
|
+
var messageStyle2 = {
|
|
269
|
+
color: theme.colors.textPrimary,
|
|
270
|
+
flex: 1,
|
|
271
|
+
fontSize: theme.fontSize.base,
|
|
272
|
+
overflow: "hidden",
|
|
273
|
+
textOverflow: "ellipsis",
|
|
274
|
+
whiteSpace: "nowrap"
|
|
275
|
+
};
|
|
276
|
+
var callerStyle2 = {
|
|
277
|
+
color: theme.colors.textDimmed,
|
|
278
|
+
flexShrink: 0,
|
|
279
|
+
fontFamily: theme.fontFamily.mono,
|
|
280
|
+
fontSize: theme.fontSize.sm,
|
|
281
|
+
maxWidth: "200px",
|
|
282
|
+
opacity: 0.7,
|
|
283
|
+
overflow: "hidden",
|
|
284
|
+
textOverflow: "ellipsis",
|
|
285
|
+
whiteSpace: "nowrap"
|
|
286
|
+
};
|
|
287
|
+
var chevronStyle = {
|
|
288
|
+
color: theme.colors.textDimmed,
|
|
289
|
+
display: "flex",
|
|
290
|
+
flexShrink: 0,
|
|
291
|
+
transition: "transform 0.15s"
|
|
292
|
+
};
|
|
293
|
+
var LogRowComponent = ({ record, expanded, onToggle }) => {
|
|
294
|
+
const levelColors = getLevelColors(record.level);
|
|
282
295
|
const handleClick = useCallback(() => {
|
|
283
296
|
onToggle(expanded ? null : record.id);
|
|
284
297
|
}, [expanded, onToggle, record.id]);
|
|
@@ -290,173 +303,119 @@ var LogRow = ({ record, expanded, onToggle }) => {
|
|
|
290
303
|
"data-lt-interactive": "",
|
|
291
304
|
"data-testid": "log-row",
|
|
292
305
|
onClick: handleClick,
|
|
293
|
-
style: {
|
|
294
|
-
alignItems: "center",
|
|
295
|
-
background: expanded ? levelColors.bg : "transparent",
|
|
296
|
-
border: "none",
|
|
297
|
-
borderBottom: `1px solid ${theme.colors.border}`,
|
|
298
|
-
cursor: "pointer",
|
|
299
|
-
display: "flex",
|
|
300
|
-
gap: theme.spacing.lg,
|
|
301
|
-
padding: `${theme.spacing.md} ${theme.spacing.xl}`,
|
|
302
|
-
textAlign: "left",
|
|
303
|
-
transition: "background 0.1s, filter 0.1s",
|
|
304
|
-
width: "100%"
|
|
305
|
-
},
|
|
306
|
+
style: { ...rowStyle, background: expanded ? levelColors.bg : "transparent" },
|
|
306
307
|
type: "button",
|
|
307
308
|
children: [
|
|
308
|
-
/* @__PURE__ */ jsx4(
|
|
309
|
-
"span",
|
|
310
|
-
{
|
|
311
|
-
style: {
|
|
312
|
-
color: theme.colors.textDimmed,
|
|
313
|
-
flexShrink: 0,
|
|
314
|
-
fontFamily: theme.fontFamily.mono,
|
|
315
|
-
fontSize: theme.fontSize.md
|
|
316
|
-
},
|
|
317
|
-
children: formatTime(record.timestamp)
|
|
318
|
-
}
|
|
319
|
-
),
|
|
309
|
+
/* @__PURE__ */ jsx4("span", { style: timestampStyle, children: formatTime(record.timestamp) }),
|
|
320
310
|
/* @__PURE__ */ jsx4(LevelBadge, { level: record.level }),
|
|
321
|
-
/* @__PURE__ */ jsx4(
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
color: theme.colors.accent,
|
|
326
|
-
flexShrink: 0,
|
|
327
|
-
fontFamily: theme.fontFamily.mono,
|
|
328
|
-
fontSize: theme.fontSize.md,
|
|
329
|
-
maxWidth: "180px",
|
|
330
|
-
overflow: "hidden",
|
|
331
|
-
textOverflow: "ellipsis",
|
|
332
|
-
whiteSpace: "nowrap"
|
|
333
|
-
},
|
|
334
|
-
children: record.category.join(".")
|
|
335
|
-
}
|
|
336
|
-
),
|
|
337
|
-
/* @__PURE__ */ jsx4(
|
|
338
|
-
"span",
|
|
339
|
-
{
|
|
340
|
-
style: {
|
|
341
|
-
color: theme.colors.textPrimary,
|
|
342
|
-
flex: 1,
|
|
343
|
-
fontSize: theme.fontSize.base,
|
|
344
|
-
overflow: "hidden",
|
|
345
|
-
textOverflow: "ellipsis",
|
|
346
|
-
whiteSpace: "nowrap"
|
|
347
|
-
},
|
|
348
|
-
children: record.messageText
|
|
349
|
-
}
|
|
350
|
-
),
|
|
351
|
-
record.caller && /* @__PURE__ */ jsx4(
|
|
352
|
-
"span",
|
|
353
|
-
{
|
|
354
|
-
style: {
|
|
355
|
-
color: theme.colors.textDimmed,
|
|
356
|
-
flexShrink: 0,
|
|
357
|
-
fontFamily: theme.fontFamily.mono,
|
|
358
|
-
fontSize: theme.fontSize.sm,
|
|
359
|
-
maxWidth: "200px",
|
|
360
|
-
opacity: 0.7,
|
|
361
|
-
overflow: "hidden",
|
|
362
|
-
textOverflow: "ellipsis",
|
|
363
|
-
whiteSpace: "nowrap"
|
|
364
|
-
},
|
|
365
|
-
children: record.caller
|
|
366
|
-
}
|
|
367
|
-
),
|
|
368
|
-
/* @__PURE__ */ jsx4(
|
|
369
|
-
"span",
|
|
370
|
-
{
|
|
371
|
-
style: {
|
|
372
|
-
color: theme.colors.textDimmed,
|
|
373
|
-
display: "flex",
|
|
374
|
-
flexShrink: 0,
|
|
375
|
-
transform: expanded ? "rotate(90deg)" : "rotate(0deg)",
|
|
376
|
-
transition: "transform 0.15s"
|
|
377
|
-
},
|
|
378
|
-
children: /* @__PURE__ */ jsx4(ChevronRightIcon, { size: 12 })
|
|
379
|
-
}
|
|
380
|
-
)
|
|
311
|
+
/* @__PURE__ */ jsx4("span", { style: categoryStyle2, children: record.category.join(".") }),
|
|
312
|
+
/* @__PURE__ */ jsx4("span", { style: messageStyle2, children: record.messageText }),
|
|
313
|
+
record.caller ? /* @__PURE__ */ jsx4("span", { style: callerStyle2, children: record.caller }) : null,
|
|
314
|
+
/* @__PURE__ */ jsx4("span", { style: { ...chevronStyle, transform: expanded ? "rotate(90deg)" : "rotate(0deg)" }, children: /* @__PURE__ */ jsx4(ChevronRightIcon, { size: 12 }) })
|
|
381
315
|
]
|
|
382
316
|
}
|
|
383
317
|
),
|
|
384
|
-
expanded
|
|
318
|
+
expanded ? /* @__PURE__ */ jsx4(LogDetail, { record }) : null
|
|
385
319
|
] });
|
|
386
320
|
};
|
|
321
|
+
var LogRow = memo(LogRowComponent);
|
|
387
322
|
|
|
388
323
|
// src/plugin/components/log-list.tsx
|
|
389
324
|
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
325
|
+
var ESTIMATED_ROW_HEIGHT = 28;
|
|
326
|
+
var OVERSCAN = 10;
|
|
327
|
+
var STICK_THRESHOLD = 40;
|
|
328
|
+
var emptyStyle = {
|
|
329
|
+
alignItems: "center",
|
|
330
|
+
color: theme.colors.textMuted,
|
|
331
|
+
display: "flex",
|
|
332
|
+
flex: 1,
|
|
333
|
+
fontSize: theme.fontSize.lg,
|
|
334
|
+
justifyContent: "center"
|
|
335
|
+
};
|
|
336
|
+
var containerStyle2 = {
|
|
337
|
+
flex: 1,
|
|
338
|
+
overflow: "auto",
|
|
339
|
+
scrollbarColor: `${theme.colors.scrollbar} transparent`,
|
|
340
|
+
scrollbarWidth: "thin"
|
|
341
|
+
};
|
|
390
342
|
var LogList = ({ records, expandedId, onToggle, autoScroll }) => {
|
|
391
343
|
const containerRef = useRef(null);
|
|
392
344
|
const isAtBottomRef = useRef(true);
|
|
345
|
+
const virtualizer = useVirtualizer({
|
|
346
|
+
count: records.length,
|
|
347
|
+
estimateSize: () => ESTIMATED_ROW_HEIGHT,
|
|
348
|
+
// The virtualizer can ask for keys of indices from a previous, longer list
|
|
349
|
+
// (after clear or a narrowing filter), so never assume the index exists.
|
|
350
|
+
getItemKey: (index) => records[index]?.id ?? index,
|
|
351
|
+
getScrollElement: () => containerRef.current,
|
|
352
|
+
overscan: OVERSCAN
|
|
353
|
+
});
|
|
393
354
|
const recordCount = records.length;
|
|
355
|
+
const lastRecordId = records[recordCount - 1]?.id;
|
|
394
356
|
useEffect(() => {
|
|
395
|
-
|
|
396
|
-
if (!(el && autoScroll && isAtBottomRef.current)) {
|
|
357
|
+
if (lastRecordId === void 0 || !(autoScroll && isAtBottomRef.current)) {
|
|
397
358
|
return;
|
|
398
359
|
}
|
|
399
|
-
|
|
400
|
-
}, [autoScroll, recordCount]);
|
|
401
|
-
|
|
360
|
+
virtualizer.scrollToIndex(recordCount - 1, { align: "end" });
|
|
361
|
+
}, [autoScroll, lastRecordId, recordCount, virtualizer]);
|
|
362
|
+
useEffect(() => {
|
|
363
|
+
if (recordCount === 0) {
|
|
364
|
+
isAtBottomRef.current = true;
|
|
365
|
+
}
|
|
366
|
+
}, [recordCount]);
|
|
367
|
+
const handleScroll = useCallback2(() => {
|
|
402
368
|
const el = containerRef.current;
|
|
403
369
|
if (!el) {
|
|
404
370
|
return;
|
|
405
371
|
}
|
|
406
|
-
isAtBottomRef.current = el.scrollHeight - el.scrollTop - el.clientHeight <
|
|
407
|
-
};
|
|
372
|
+
isAtBottomRef.current = el.scrollHeight - el.scrollTop - el.clientHeight < STICK_THRESHOLD;
|
|
373
|
+
}, []);
|
|
408
374
|
if (records.length === 0) {
|
|
409
|
-
return /* @__PURE__ */ jsx5(
|
|
410
|
-
"div",
|
|
411
|
-
{
|
|
412
|
-
"data-testid": "log-list-empty",
|
|
413
|
-
style: {
|
|
414
|
-
alignItems: "center",
|
|
415
|
-
color: theme.colors.textMuted,
|
|
416
|
-
display: "flex",
|
|
417
|
-
flex: 1,
|
|
418
|
-
fontSize: theme.fontSize.lg,
|
|
419
|
-
justifyContent: "center"
|
|
420
|
-
},
|
|
421
|
-
children: "No logs yet"
|
|
422
|
-
}
|
|
423
|
-
);
|
|
375
|
+
return /* @__PURE__ */ jsx5("div", { "data-testid": "log-list-empty", style: emptyStyle, children: "No logs yet" });
|
|
424
376
|
}
|
|
425
|
-
|
|
377
|
+
const virtualItems = virtualizer.getVirtualItems();
|
|
378
|
+
return /* @__PURE__ */ jsx5("div", { "data-testid": "log-list", onScroll: handleScroll, ref: containerRef, style: containerStyle2, children: /* @__PURE__ */ jsx5(
|
|
426
379
|
"div",
|
|
427
380
|
{
|
|
428
|
-
"data-testid": "log-list",
|
|
429
|
-
onScroll: handleScroll,
|
|
430
|
-
ref: containerRef,
|
|
431
381
|
style: {
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
scrollbarWidth: "thin"
|
|
382
|
+
height: `${virtualizer.getTotalSize()}px`,
|
|
383
|
+
position: "relative",
|
|
384
|
+
width: "100%"
|
|
436
385
|
},
|
|
437
|
-
children:
|
|
438
|
-
|
|
386
|
+
children: /* @__PURE__ */ jsx5(
|
|
387
|
+
"div",
|
|
439
388
|
{
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
389
|
+
style: {
|
|
390
|
+
left: 0,
|
|
391
|
+
position: "absolute",
|
|
392
|
+
top: 0,
|
|
393
|
+
transform: `translateY(${virtualItems[0]?.start ?? 0}px)`,
|
|
394
|
+
width: "100%"
|
|
395
|
+
},
|
|
396
|
+
children: virtualItems.map((virtualItem) => {
|
|
397
|
+
const record = records[virtualItem.index];
|
|
398
|
+
return /* @__PURE__ */ jsx5(
|
|
399
|
+
"div",
|
|
400
|
+
{
|
|
401
|
+
"data-index": virtualItem.index,
|
|
402
|
+
ref: virtualizer.measureElement,
|
|
403
|
+
children: /* @__PURE__ */ jsx5(LogRow, { expanded: expandedId === record.id, onToggle, record })
|
|
404
|
+
},
|
|
405
|
+
virtualItem.key
|
|
406
|
+
);
|
|
407
|
+
})
|
|
408
|
+
}
|
|
409
|
+
)
|
|
446
410
|
}
|
|
447
|
-
);
|
|
411
|
+
) });
|
|
448
412
|
};
|
|
449
413
|
|
|
450
414
|
// src/plugin/components/toolbar.tsx
|
|
451
415
|
import { Combobox } from "@base-ui-components/react/combobox";
|
|
452
416
|
import { Popover } from "@base-ui-components/react/popover";
|
|
453
417
|
import { Debouncer } from "@tanstack/pacer";
|
|
454
|
-
import { useCallback as
|
|
455
|
-
|
|
456
|
-
// src/types.ts
|
|
457
|
-
var LOG_LEVELS = ["trace", "debug", "info", "warning", "error", "fatal"];
|
|
458
|
-
|
|
459
|
-
// src/plugin/components/toolbar.tsx
|
|
418
|
+
import { useCallback as useCallback3, useEffect as useEffect2, useMemo, useState } from "react";
|
|
460
419
|
import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
461
420
|
var HOVER_STYLE_ID = "logtape-devtools-hover";
|
|
462
421
|
function useHoverStyles() {
|
|
@@ -473,6 +432,11 @@ function useHoverStyles() {
|
|
|
473
432
|
[data-lt-interactive]:active {
|
|
474
433
|
filter: brightness(0.9);
|
|
475
434
|
}
|
|
435
|
+
[data-lt-interactive]:focus-visible,
|
|
436
|
+
[data-lt-input]:focus-visible {
|
|
437
|
+
outline: 2px solid ${theme.colors.accent};
|
|
438
|
+
outline-offset: 1px;
|
|
439
|
+
}
|
|
476
440
|
[data-lt-clear-btn]:hover {
|
|
477
441
|
color: ${theme.colors.textPrimary} !important;
|
|
478
442
|
}
|
|
@@ -518,14 +482,15 @@ var sectionLabelStyle = {
|
|
|
518
482
|
var LevelToggle = ({
|
|
519
483
|
level,
|
|
520
484
|
active,
|
|
485
|
+
pressed,
|
|
521
486
|
onToggle
|
|
522
487
|
}) => {
|
|
523
488
|
const colors = theme.colors.levels[level];
|
|
524
|
-
const handleClick =
|
|
489
|
+
const handleClick = useCallback3(() => onToggle(level), [level, onToggle]);
|
|
525
490
|
return /* @__PURE__ */ jsx6(
|
|
526
491
|
"button",
|
|
527
492
|
{
|
|
528
|
-
"aria-pressed":
|
|
493
|
+
"aria-pressed": pressed,
|
|
529
494
|
"data-lt-interactive": "",
|
|
530
495
|
"data-testid": `level-toggle-${level}`,
|
|
531
496
|
onClick: handleClick,
|
|
@@ -561,32 +526,26 @@ var Toolbar = ({
|
|
|
561
526
|
categories,
|
|
562
527
|
categoryFilter,
|
|
563
528
|
onCategoryFilterChange,
|
|
564
|
-
searchText,
|
|
565
529
|
onSearchTextChange,
|
|
566
530
|
totalCount,
|
|
567
531
|
filteredCount
|
|
568
532
|
}) => {
|
|
569
533
|
useHoverStyles();
|
|
570
|
-
const [
|
|
534
|
+
const [search, setSearch] = useState("");
|
|
571
535
|
const debouncedSearch = useMemo(
|
|
572
536
|
() => new Debouncer(onSearchTextChange, { wait: 200 }),
|
|
573
537
|
[onSearchTextChange]
|
|
574
538
|
);
|
|
575
539
|
useEffect2(() => () => debouncedSearch.cancel(), [debouncedSearch]);
|
|
576
|
-
const handleSearchChange =
|
|
540
|
+
const handleSearchChange = useCallback3(
|
|
577
541
|
(e) => {
|
|
578
|
-
const value = e.target
|
|
579
|
-
|
|
542
|
+
const { value } = e.target;
|
|
543
|
+
setSearch(value);
|
|
580
544
|
debouncedSearch.maybeExecute(value);
|
|
581
545
|
},
|
|
582
546
|
[debouncedSearch]
|
|
583
547
|
);
|
|
584
|
-
|
|
585
|
-
if (searchText === "" && localSearch !== "") {
|
|
586
|
-
setLocalSearch("");
|
|
587
|
-
}
|
|
588
|
-
}, [searchText, localSearch]);
|
|
589
|
-
const handleLevelToggle = useCallback2(
|
|
548
|
+
const handleLevelToggle = useCallback3(
|
|
590
549
|
(level) => {
|
|
591
550
|
const next = new Set(levelFilter);
|
|
592
551
|
if (next.has(level)) {
|
|
@@ -699,7 +658,8 @@ var Toolbar = ({
|
|
|
699
658
|
{
|
|
700
659
|
active: levelFilter.size === 0 || levelFilter.has(level),
|
|
701
660
|
level,
|
|
702
|
-
onToggle: handleLevelToggle
|
|
661
|
+
onToggle: handleLevelToggle,
|
|
662
|
+
pressed: levelFilter.has(level)
|
|
703
663
|
},
|
|
704
664
|
level
|
|
705
665
|
))
|
|
@@ -835,6 +795,8 @@ var Toolbar = ({
|
|
|
835
795
|
/* @__PURE__ */ jsx6(
|
|
836
796
|
Combobox.Input,
|
|
837
797
|
{
|
|
798
|
+
"aria-label": "Filter by category",
|
|
799
|
+
"data-lt-input": "",
|
|
838
800
|
"data-testid": "category-input",
|
|
839
801
|
placeholder: categoryFilter.length === 0 ? "Category\u2026" : "",
|
|
840
802
|
style: {
|
|
@@ -901,12 +863,14 @@ var Toolbar = ({
|
|
|
901
863
|
/* @__PURE__ */ jsx6(
|
|
902
864
|
"input",
|
|
903
865
|
{
|
|
866
|
+
"aria-label": "Search logs",
|
|
867
|
+
"data-lt-input": "",
|
|
904
868
|
"data-testid": "search-input",
|
|
905
869
|
onChange: handleSearchChange,
|
|
906
870
|
placeholder: "Search\u2026",
|
|
907
871
|
style: inputStyle,
|
|
908
872
|
type: "text",
|
|
909
|
-
value:
|
|
873
|
+
value: search
|
|
910
874
|
}
|
|
911
875
|
)
|
|
912
876
|
] })
|
|
@@ -917,6 +881,61 @@ var Toolbar = ({
|
|
|
917
881
|
|
|
918
882
|
// src/plugin/logtape-devtools-plugin.tsx
|
|
919
883
|
import { Fragment, jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
884
|
+
var rootStyle = {
|
|
885
|
+
background: theme.colors.background,
|
|
886
|
+
color: theme.colors.textPrimary,
|
|
887
|
+
display: "flex",
|
|
888
|
+
flexDirection: "row",
|
|
889
|
+
fontFamily: theme.fontFamily.sans,
|
|
890
|
+
height: "100%",
|
|
891
|
+
overflow: "hidden"
|
|
892
|
+
};
|
|
893
|
+
var sidebarStyle = {
|
|
894
|
+
flexShrink: 0,
|
|
895
|
+
overflow: "hidden",
|
|
896
|
+
transition: "width 0.2s ease, opacity 0.15s ease"
|
|
897
|
+
};
|
|
898
|
+
var mainStyle = {
|
|
899
|
+
display: "flex",
|
|
900
|
+
flex: 1,
|
|
901
|
+
flexDirection: "column",
|
|
902
|
+
overflow: "hidden"
|
|
903
|
+
};
|
|
904
|
+
var topBarStyle = {
|
|
905
|
+
alignItems: "center",
|
|
906
|
+
borderBottom: `1px solid ${theme.colors.border}`,
|
|
907
|
+
display: "flex",
|
|
908
|
+
flexShrink: 0,
|
|
909
|
+
gap: theme.spacing.lg,
|
|
910
|
+
padding: `${theme.spacing.sm} ${theme.spacing.lg}`
|
|
911
|
+
};
|
|
912
|
+
var sidebarToggleStyle = {
|
|
913
|
+
background: "none",
|
|
914
|
+
border: "none",
|
|
915
|
+
color: theme.colors.textMuted,
|
|
916
|
+
cursor: "pointer",
|
|
917
|
+
fontFamily: theme.fontFamily.sans,
|
|
918
|
+
fontSize: theme.fontSize.md,
|
|
919
|
+
padding: `${theme.spacing.xs} ${theme.spacing.sm}`,
|
|
920
|
+
transition: "color 0.1s"
|
|
921
|
+
};
|
|
922
|
+
var iconLabelStyle = { alignItems: "center", display: "inline-flex", gap: "6px" };
|
|
923
|
+
var countStyle = {
|
|
924
|
+
color: theme.colors.textMuted,
|
|
925
|
+
fontFamily: theme.fontFamily.mono,
|
|
926
|
+
fontSize: theme.fontSize.sm
|
|
927
|
+
};
|
|
928
|
+
var compactButtonStyle = {
|
|
929
|
+
background: theme.colors.surfaceHover,
|
|
930
|
+
border: `1px solid ${theme.colors.border}`,
|
|
931
|
+
borderRadius: theme.radius.sm,
|
|
932
|
+
color: theme.colors.textPrimary,
|
|
933
|
+
cursor: "pointer",
|
|
934
|
+
fontFamily: theme.fontFamily.sans,
|
|
935
|
+
fontSize: theme.fontSize.sm,
|
|
936
|
+
padding: `${theme.spacing.xs} ${theme.spacing.sm}`,
|
|
937
|
+
transition: "filter 0.1s"
|
|
938
|
+
};
|
|
920
939
|
var LogTapeDevtoolsPlugin = ({ store }) => {
|
|
921
940
|
const allRecords = useSyncExternalStore(store.subscribe, store.getSnapshot, store.getSnapshot);
|
|
922
941
|
const [paused, setPaused] = useState2(false);
|
|
@@ -926,15 +945,15 @@ var LogTapeDevtoolsPlugin = ({ store }) => {
|
|
|
926
945
|
const [searchText, setSearchText] = useState2("");
|
|
927
946
|
const [expandedId, setExpandedId] = useState2(null);
|
|
928
947
|
const [sidebarOpen, setSidebarOpen] = useState2(true);
|
|
929
|
-
const handlePause =
|
|
948
|
+
const handlePause = useCallback4(() => {
|
|
930
949
|
setPaused(true);
|
|
931
950
|
setPausedRecords(store.getSnapshot());
|
|
932
951
|
}, [store]);
|
|
933
|
-
const handleResume =
|
|
952
|
+
const handleResume = useCallback4(() => {
|
|
934
953
|
setPaused(false);
|
|
935
954
|
setPausedRecords([]);
|
|
936
955
|
}, []);
|
|
937
|
-
const handleClear =
|
|
956
|
+
const handleClear = useCallback4(() => {
|
|
938
957
|
store.clear();
|
|
939
958
|
setPausedRecords([]);
|
|
940
959
|
setExpandedId(null);
|
|
@@ -947,8 +966,8 @@ var LogTapeDevtoolsPlugin = ({ store }) => {
|
|
|
947
966
|
}
|
|
948
967
|
return Array.from(seen).sort();
|
|
949
968
|
}, [records]);
|
|
950
|
-
const filteredRecords = useMemo2(
|
|
951
|
-
|
|
969
|
+
const filteredRecords = useMemo2(
|
|
970
|
+
() => records.filter((r) => {
|
|
952
971
|
if (levelFilter.size > 0 && !levelFilter.has(r.level)) {
|
|
953
972
|
return false;
|
|
954
973
|
}
|
|
@@ -962,160 +981,96 @@ var LogTapeDevtoolsPlugin = ({ store }) => {
|
|
|
962
981
|
}
|
|
963
982
|
}
|
|
964
983
|
return true;
|
|
965
|
-
})
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
984
|
+
}),
|
|
985
|
+
[records, levelFilter, categoryFilter, searchText]
|
|
986
|
+
);
|
|
987
|
+
return /* @__PURE__ */ jsxs5("div", { style: rootStyle, children: [
|
|
988
|
+
/* @__PURE__ */ jsx7(
|
|
989
|
+
"div",
|
|
990
|
+
{
|
|
991
|
+
style: {
|
|
992
|
+
...sidebarStyle,
|
|
993
|
+
borderRight: sidebarOpen ? `1px solid ${theme.colors.border}` : "none",
|
|
994
|
+
opacity: sidebarOpen ? 1 : 0,
|
|
995
|
+
width: sidebarOpen ? "200px" : "0px"
|
|
996
|
+
},
|
|
997
|
+
children: /* @__PURE__ */ jsx7(
|
|
998
|
+
Toolbar,
|
|
999
|
+
{
|
|
1000
|
+
categories: uniqueCategories,
|
|
1001
|
+
categoryFilter,
|
|
1002
|
+
filteredCount: filteredRecords.length,
|
|
1003
|
+
levelFilter,
|
|
1004
|
+
onCategoryFilterChange: setCategoryFilter,
|
|
1005
|
+
onClear: handleClear,
|
|
1006
|
+
onLevelFilterChange: setLevelFilter,
|
|
1007
|
+
onPause: handlePause,
|
|
1008
|
+
onResume: handleResume,
|
|
1009
|
+
onSearchTextChange: setSearchText,
|
|
1010
|
+
paused,
|
|
1011
|
+
totalCount: records.length
|
|
1012
|
+
}
|
|
1013
|
+
)
|
|
1014
|
+
}
|
|
1015
|
+
),
|
|
1016
|
+
/* @__PURE__ */ jsxs5("div", { style: mainStyle, children: [
|
|
1017
|
+
/* @__PURE__ */ jsxs5("div", { style: topBarStyle, children: [
|
|
980
1018
|
/* @__PURE__ */ jsx7(
|
|
981
|
-
"
|
|
1019
|
+
"button",
|
|
982
1020
|
{
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
{
|
|
994
|
-
categories: uniqueCategories,
|
|
995
|
-
categoryFilter,
|
|
996
|
-
filteredCount: filteredRecords.length,
|
|
997
|
-
levelFilter,
|
|
998
|
-
onCategoryFilterChange: setCategoryFilter,
|
|
999
|
-
onClear: handleClear,
|
|
1000
|
-
onLevelFilterChange: setLevelFilter,
|
|
1001
|
-
onPause: handlePause,
|
|
1002
|
-
onResume: handleResume,
|
|
1003
|
-
onSearchTextChange: setSearchText,
|
|
1004
|
-
paused,
|
|
1005
|
-
searchText,
|
|
1006
|
-
totalCount: records.length
|
|
1007
|
-
}
|
|
1008
|
-
)
|
|
1021
|
+
"aria-expanded": sidebarOpen,
|
|
1022
|
+
"data-lt-clear-btn": "",
|
|
1023
|
+
onClick: () => setSidebarOpen((v) => !v),
|
|
1024
|
+
style: sidebarToggleStyle,
|
|
1025
|
+
title: sidebarOpen ? "Collapse sidebar" : "Expand sidebar",
|
|
1026
|
+
type: "button",
|
|
1027
|
+
children: /* @__PURE__ */ jsxs5("span", { style: iconLabelStyle, children: [
|
|
1028
|
+
sidebarOpen ? /* @__PURE__ */ jsx7(PanelLeftCloseIcon, { size: 14 }) : /* @__PURE__ */ jsx7(PanelLeftOpenIcon, { size: 14 }),
|
|
1029
|
+
sidebarOpen ? "Hide controls" : "Show controls"
|
|
1030
|
+
] })
|
|
1009
1031
|
}
|
|
1010
1032
|
),
|
|
1011
|
-
/* @__PURE__ */ jsxs5(
|
|
1012
|
-
/* @__PURE__ */
|
|
1013
|
-
|
|
1033
|
+
!sidebarOpen && /* @__PURE__ */ jsxs5(Fragment, { children: [
|
|
1034
|
+
/* @__PURE__ */ jsx7("span", { style: countStyle, children: filteredRecords.length === records.length ? `${records.length} logs` : `${filteredRecords.length} / ${records.length} logs` }),
|
|
1035
|
+
/* @__PURE__ */ jsx7(
|
|
1036
|
+
"button",
|
|
1014
1037
|
{
|
|
1038
|
+
"data-lt-interactive": "",
|
|
1039
|
+
onClick: paused ? handleResume : handlePause,
|
|
1015
1040
|
style: {
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
flexShrink: 0,
|
|
1020
|
-
gap: theme.spacing.lg,
|
|
1021
|
-
padding: `${theme.spacing.sm} ${theme.spacing.lg}`
|
|
1041
|
+
...compactButtonStyle,
|
|
1042
|
+
background: paused ? theme.colors.levels.warning.badge : compactButtonStyle.background,
|
|
1043
|
+
color: paused ? theme.colors.white : compactButtonStyle.color
|
|
1022
1044
|
},
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
{
|
|
1027
|
-
"aria-expanded": sidebarOpen,
|
|
1028
|
-
"data-lt-clear-btn": "",
|
|
1029
|
-
onClick: () => setSidebarOpen((v) => !v),
|
|
1030
|
-
style: {
|
|
1031
|
-
background: "none",
|
|
1032
|
-
border: "none",
|
|
1033
|
-
color: theme.colors.textMuted,
|
|
1034
|
-
cursor: "pointer",
|
|
1035
|
-
fontFamily: theme.fontFamily.sans,
|
|
1036
|
-
fontSize: theme.fontSize.md,
|
|
1037
|
-
padding: `${theme.spacing.xs} ${theme.spacing.sm}`,
|
|
1038
|
-
transition: "color 0.1s"
|
|
1039
|
-
},
|
|
1040
|
-
title: sidebarOpen ? "Collapse sidebar" : "Expand sidebar",
|
|
1041
|
-
type: "button",
|
|
1042
|
-
children: /* @__PURE__ */ jsxs5("span", { style: { alignItems: "center", display: "inline-flex", gap: "6px" }, children: [
|
|
1043
|
-
sidebarOpen ? /* @__PURE__ */ jsx7(PanelLeftCloseIcon, { size: 14 }) : /* @__PURE__ */ jsx7(PanelLeftOpenIcon, { size: 14 }),
|
|
1044
|
-
sidebarOpen ? "Hide controls" : "Show controls"
|
|
1045
|
-
] })
|
|
1046
|
-
}
|
|
1047
|
-
),
|
|
1048
|
-
!sidebarOpen && /* @__PURE__ */ jsxs5(Fragment, { children: [
|
|
1049
|
-
/* @__PURE__ */ jsx7(
|
|
1050
|
-
"span",
|
|
1051
|
-
{
|
|
1052
|
-
style: {
|
|
1053
|
-
color: theme.colors.textMuted,
|
|
1054
|
-
fontFamily: theme.fontFamily.mono,
|
|
1055
|
-
fontSize: theme.fontSize.sm
|
|
1056
|
-
},
|
|
1057
|
-
children: filteredRecords.length === records.length ? `${records.length} logs` : `${filteredRecords.length} / ${records.length} logs`
|
|
1058
|
-
}
|
|
1059
|
-
),
|
|
1060
|
-
/* @__PURE__ */ jsx7(
|
|
1061
|
-
"button",
|
|
1062
|
-
{
|
|
1063
|
-
"data-lt-interactive": "",
|
|
1064
|
-
onClick: paused ? handleResume : handlePause,
|
|
1065
|
-
style: {
|
|
1066
|
-
background: paused ? theme.colors.levels.warning.badge : theme.colors.surfaceHover,
|
|
1067
|
-
border: `1px solid ${theme.colors.border}`,
|
|
1068
|
-
borderRadius: theme.radius.sm,
|
|
1069
|
-
color: paused ? theme.colors.white : theme.colors.textPrimary,
|
|
1070
|
-
cursor: "pointer",
|
|
1071
|
-
fontFamily: theme.fontFamily.sans,
|
|
1072
|
-
fontSize: theme.fontSize.sm,
|
|
1073
|
-
padding: `${theme.spacing.xs} ${theme.spacing.sm}`,
|
|
1074
|
-
transition: "filter 0.1s"
|
|
1075
|
-
},
|
|
1076
|
-
title: paused ? "Resume" : "Pause",
|
|
1077
|
-
type: "button",
|
|
1078
|
-
children: paused ? /* @__PURE__ */ jsx7(PlayIcon, { size: 12 }) : /* @__PURE__ */ jsx7(PauseIcon, { size: 12 })
|
|
1079
|
-
}
|
|
1080
|
-
),
|
|
1081
|
-
/* @__PURE__ */ jsx7(
|
|
1082
|
-
"button",
|
|
1083
|
-
{
|
|
1084
|
-
"data-lt-interactive": "",
|
|
1085
|
-
onClick: handleClear,
|
|
1086
|
-
style: {
|
|
1087
|
-
background: theme.colors.surfaceHover,
|
|
1088
|
-
border: `1px solid ${theme.colors.border}`,
|
|
1089
|
-
borderRadius: theme.radius.sm,
|
|
1090
|
-
color: theme.colors.textPrimary,
|
|
1091
|
-
cursor: "pointer",
|
|
1092
|
-
fontFamily: theme.fontFamily.sans,
|
|
1093
|
-
fontSize: theme.fontSize.sm,
|
|
1094
|
-
padding: `${theme.spacing.xs} ${theme.spacing.sm}`,
|
|
1095
|
-
transition: "filter 0.1s"
|
|
1096
|
-
},
|
|
1097
|
-
title: "Clear",
|
|
1098
|
-
type: "button",
|
|
1099
|
-
children: /* @__PURE__ */ jsx7(Trash2Icon, { size: 12 })
|
|
1100
|
-
}
|
|
1101
|
-
)
|
|
1102
|
-
] })
|
|
1103
|
-
]
|
|
1045
|
+
title: paused ? "Resume" : "Pause",
|
|
1046
|
+
type: "button",
|
|
1047
|
+
children: paused ? /* @__PURE__ */ jsx7(PlayIcon, { size: 12 }) : /* @__PURE__ */ jsx7(PauseIcon, { size: 12 })
|
|
1104
1048
|
}
|
|
1105
1049
|
),
|
|
1106
1050
|
/* @__PURE__ */ jsx7(
|
|
1107
|
-
|
|
1051
|
+
"button",
|
|
1108
1052
|
{
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1053
|
+
"data-lt-interactive": "",
|
|
1054
|
+
onClick: handleClear,
|
|
1055
|
+
style: compactButtonStyle,
|
|
1056
|
+
title: "Clear",
|
|
1057
|
+
type: "button",
|
|
1058
|
+
children: /* @__PURE__ */ jsx7(Trash2Icon, { size: 12 })
|
|
1113
1059
|
}
|
|
1114
1060
|
)
|
|
1115
1061
|
] })
|
|
1116
|
-
]
|
|
1117
|
-
|
|
1118
|
-
|
|
1062
|
+
] }),
|
|
1063
|
+
/* @__PURE__ */ jsx7(
|
|
1064
|
+
LogList,
|
|
1065
|
+
{
|
|
1066
|
+
autoScroll: !paused,
|
|
1067
|
+
expandedId,
|
|
1068
|
+
onToggle: setExpandedId,
|
|
1069
|
+
records: filteredRecords
|
|
1070
|
+
}
|
|
1071
|
+
)
|
|
1072
|
+
] })
|
|
1073
|
+
] });
|
|
1119
1074
|
};
|
|
1120
1075
|
|
|
1121
1076
|
// src/plugin/create-logtape-devtools-plugin.tsx
|
|
@@ -1127,113 +1082,19 @@ var createLogTapeDevtoolsPlugin = (options) => ({
|
|
|
1127
1082
|
render: /* @__PURE__ */ jsx8(LogTapeDevtoolsPlugin, { store: options?.store ?? defaultLogStore })
|
|
1128
1083
|
});
|
|
1129
1084
|
|
|
1130
|
-
// src/
|
|
1131
|
-
function
|
|
1132
|
-
return message.map((part) => {
|
|
1133
|
-
if (typeof part === "string") {
|
|
1134
|
-
return part;
|
|
1135
|
-
}
|
|
1136
|
-
if (part === null || part === void 0) {
|
|
1137
|
-
return String(part);
|
|
1138
|
-
}
|
|
1139
|
-
try {
|
|
1140
|
-
return JSON.stringify(part);
|
|
1141
|
-
} catch {
|
|
1142
|
-
return String(part);
|
|
1143
|
-
}
|
|
1144
|
-
}).join("");
|
|
1145
|
-
}
|
|
1146
|
-
function safeCloneProperties(properties) {
|
|
1147
|
-
try {
|
|
1148
|
-
return JSON.parse(JSON.stringify(properties));
|
|
1149
|
-
} catch {
|
|
1150
|
-
const result = {};
|
|
1151
|
-
for (const [key, value] of Object.entries(properties)) {
|
|
1152
|
-
try {
|
|
1153
|
-
result[key] = JSON.parse(JSON.stringify(value));
|
|
1154
|
-
} catch {
|
|
1155
|
-
result[key] = String(value);
|
|
1156
|
-
}
|
|
1157
|
-
}
|
|
1158
|
-
return result;
|
|
1159
|
-
}
|
|
1160
|
-
}
|
|
1161
|
-
var v8FrameRe = /at\s+(?:.*?\s+\()?(.+?):(\d+):(\d+)\)?$/;
|
|
1162
|
-
var smFrameRe = /(?:^|@)(.+?):(\d+):(\d+)$/;
|
|
1163
|
-
function captureCallerInfo() {
|
|
1164
|
-
const stack = new Error().stack;
|
|
1165
|
-
if (!stack) {
|
|
1166
|
-
return void 0;
|
|
1167
|
-
}
|
|
1168
|
-
const lines = stack.split("\n");
|
|
1169
|
-
for (const line of lines) {
|
|
1170
|
-
const trimmed = line.trim();
|
|
1171
|
-
if (!trimmed || trimmed === "Error") {
|
|
1172
|
-
continue;
|
|
1173
|
-
}
|
|
1174
|
-
if (/logtape/i.test(trimmed)) {
|
|
1175
|
-
continue;
|
|
1176
|
-
}
|
|
1177
|
-
const match = v8FrameRe.exec(trimmed) ?? smFrameRe.exec(trimmed);
|
|
1178
|
-
if (!match) {
|
|
1179
|
-
continue;
|
|
1180
|
-
}
|
|
1181
|
-
const [, filePath, lineNo, colNo] = match;
|
|
1182
|
-
const fileName = filePath.replace(/[?#].*$/, "").split("/").pop() ?? filePath;
|
|
1183
|
-
return `${fileName}:${lineNo}:${colNo}`;
|
|
1184
|
-
}
|
|
1185
|
-
return void 0;
|
|
1186
|
-
}
|
|
1187
|
-
function normalizeRecord(record, captureStack, id) {
|
|
1188
|
-
const normalized = {
|
|
1189
|
-
id,
|
|
1190
|
-
timestamp: record.timestamp,
|
|
1191
|
-
level: record.level,
|
|
1192
|
-
category: [...record.category],
|
|
1193
|
-
message: [...record.message],
|
|
1194
|
-
messageText: renderMessage(record.message),
|
|
1195
|
-
properties: safeCloneProperties(record.properties)
|
|
1196
|
-
};
|
|
1197
|
-
if (captureStack) {
|
|
1198
|
-
const caller = captureCallerInfo();
|
|
1199
|
-
if (caller) {
|
|
1200
|
-
normalized.caller = caller;
|
|
1201
|
-
}
|
|
1202
|
-
}
|
|
1203
|
-
return normalized;
|
|
1204
|
-
}
|
|
1205
|
-
function isProductionEnv() {
|
|
1206
|
-
try {
|
|
1207
|
-
if (typeof process !== "undefined" && process.env?.NODE_ENV === "production") {
|
|
1208
|
-
return true;
|
|
1209
|
-
}
|
|
1210
|
-
} catch {
|
|
1211
|
-
}
|
|
1212
|
-
return false;
|
|
1213
|
-
}
|
|
1214
|
-
function createDevtoolsSink(options) {
|
|
1085
|
+
// src/create-logtape-devtools.ts
|
|
1086
|
+
function createLogTapeDevtools(options) {
|
|
1215
1087
|
const store = options?.store ?? defaultLogStore;
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
let counter = 0;
|
|
1220
|
-
return (record) => {
|
|
1221
|
-
try {
|
|
1222
|
-
const normalized = normalizeRecord(
|
|
1223
|
-
record,
|
|
1224
|
-
captureStack,
|
|
1225
|
-
`log-${sinkId}-${++counter}-${record.timestamp}`
|
|
1226
|
-
);
|
|
1227
|
-
store.addRecord(normalized);
|
|
1228
|
-
} catch {
|
|
1229
|
-
}
|
|
1088
|
+
return {
|
|
1089
|
+
plugin: createLogTapeDevtoolsPlugin({ ...options?.plugin, store }),
|
|
1090
|
+
sink: createDevtoolsSink({ ...options?.sink, store })
|
|
1230
1091
|
};
|
|
1231
1092
|
}
|
|
1232
1093
|
export {
|
|
1233
1094
|
LOG_LEVELS,
|
|
1234
|
-
LogTapeDevtoolsPlugin,
|
|
1235
1095
|
createDevtoolsSink,
|
|
1236
1096
|
createLogStore,
|
|
1097
|
+
createLogTapeDevtools,
|
|
1237
1098
|
createLogTapeDevtoolsPlugin,
|
|
1238
1099
|
defaultLogStore
|
|
1239
1100
|
};
|