react-dev-panel 0.1.0 → 0.2.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/dist/index.cjs +1273 -828
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -6
- package/dist/index.d.ts +4 -6
- package/dist/index.js +1255 -829
- package/dist/index.js.map +1 -1
- package/package.json +9 -1
package/dist/index.cjs
CHANGED
|
@@ -1,378 +1,808 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
var Box6 = require('@mui/material/Box');
|
|
4
|
+
var Chip = require('@mui/material/Chip');
|
|
5
|
+
var Stack = require('@mui/material/Stack');
|
|
6
|
+
var Tooltip2 = require('@mui/material/Tooltip');
|
|
7
|
+
var Collapse = require('@mui/material/Collapse');
|
|
8
|
+
var TextField = require('@mui/material/TextField');
|
|
9
|
+
var Typography = require('@mui/material/Typography');
|
|
10
|
+
var IconButton = require('@mui/material/IconButton');
|
|
11
|
+
var ToggleButton = require('@mui/material/ToggleButton');
|
|
12
|
+
var styles = require('@mui/material/styles');
|
|
13
|
+
var InputAdornment = require('@mui/material/InputAdornment');
|
|
14
|
+
var ToggleButtonGroup = require('@mui/material/ToggleButtonGroup');
|
|
3
15
|
var react = require('react');
|
|
16
|
+
var lu = require('react-icons/lu');
|
|
4
17
|
var jsxRuntime = require('react/jsx-runtime');
|
|
5
18
|
var webVitals = require('web-vitals');
|
|
19
|
+
var Switch = require('@mui/material/Switch');
|
|
20
|
+
var Divider = require('@mui/material/Divider');
|
|
21
|
+
var Button = require('@mui/material/Button');
|
|
22
|
+
var Fab = require('@mui/material/Fab');
|
|
23
|
+
var Menu = require('@mui/material/Menu');
|
|
24
|
+
var MenuItem = require('@mui/material/MenuItem');
|
|
25
|
+
|
|
26
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
27
|
+
|
|
28
|
+
var Box6__default = /*#__PURE__*/_interopDefault(Box6);
|
|
29
|
+
var Chip__default = /*#__PURE__*/_interopDefault(Chip);
|
|
30
|
+
var Stack__default = /*#__PURE__*/_interopDefault(Stack);
|
|
31
|
+
var Tooltip2__default = /*#__PURE__*/_interopDefault(Tooltip2);
|
|
32
|
+
var Collapse__default = /*#__PURE__*/_interopDefault(Collapse);
|
|
33
|
+
var TextField__default = /*#__PURE__*/_interopDefault(TextField);
|
|
34
|
+
var Typography__default = /*#__PURE__*/_interopDefault(Typography);
|
|
35
|
+
var IconButton__default = /*#__PURE__*/_interopDefault(IconButton);
|
|
36
|
+
var ToggleButton__default = /*#__PURE__*/_interopDefault(ToggleButton);
|
|
37
|
+
var InputAdornment__default = /*#__PURE__*/_interopDefault(InputAdornment);
|
|
38
|
+
var ToggleButtonGroup__default = /*#__PURE__*/_interopDefault(ToggleButtonGroup);
|
|
39
|
+
var Switch__default = /*#__PURE__*/_interopDefault(Switch);
|
|
40
|
+
var Divider__default = /*#__PURE__*/_interopDefault(Divider);
|
|
41
|
+
var Button__default = /*#__PURE__*/_interopDefault(Button);
|
|
42
|
+
var Fab__default = /*#__PURE__*/_interopDefault(Fab);
|
|
43
|
+
var Menu__default = /*#__PURE__*/_interopDefault(Menu);
|
|
44
|
+
var MenuItem__default = /*#__PURE__*/_interopDefault(MenuItem);
|
|
6
45
|
|
|
7
46
|
// src/tools/dev-logs/index.tsx
|
|
8
47
|
|
|
9
|
-
// src/core/
|
|
10
|
-
var
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
.rdp-root, .rdp-root * { box-sizing: border-box; }
|
|
14
|
-
.rdp-root {
|
|
15
|
-
--rdp-bg: #11161d;
|
|
16
|
-
--rdp-bg-elev: #1a212b;
|
|
17
|
-
--rdp-bg-soft: rgba(148,163,184,0.06);
|
|
18
|
-
--rdp-border: rgba(255,255,255,0.09);
|
|
19
|
-
--rdp-text: #e6e9ee;
|
|
20
|
-
--rdp-text-dim: #9aa4b2;
|
|
21
|
-
--rdp-text-faint: #6b7585;
|
|
22
|
-
--rdp-accent: #6950E8;
|
|
23
|
-
--rdp-accent-contrast: #ffffff;
|
|
24
|
-
--rdp-success: #3ddc84;
|
|
25
|
-
--rdp-warning: #e0a82e;
|
|
26
|
-
--rdp-error: #e5575c;
|
|
27
|
-
--rdp-info: #56a6e8;
|
|
28
|
-
--rdp-radius: 10px;
|
|
29
|
-
--rdp-shadow: 0 8px 28px rgba(0,0,0,0.5);
|
|
30
|
-
--rdp-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
|
|
31
|
-
--rdp-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
|
32
|
-
color: var(--rdp-text);
|
|
33
|
-
font-family: var(--rdp-sans);
|
|
34
|
-
font-size: 13px;
|
|
35
|
-
line-height: 1.4;
|
|
48
|
+
// src/core/registry.ts
|
|
49
|
+
var tools = /* @__PURE__ */ new Map();
|
|
50
|
+
function registerTool(def) {
|
|
51
|
+
tools.set(def.id, def);
|
|
36
52
|
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
.rdp-fab {
|
|
40
|
-
position: fixed; width: 52px; height: 52px; border-radius: 50%;
|
|
41
|
-
display: grid; place-items: center; cursor: grab; border: none;
|
|
42
|
-
color: var(--rdp-accent-contrast);
|
|
43
|
-
background: linear-gradient(135deg, var(--rdp-accent), #4a36b8);
|
|
44
|
-
box-shadow: 0 4px 12px rgba(105,80,232,0.35), 0 8px 24px rgba(0,0,0,0.5);
|
|
45
|
-
z-index: ${RDP_Z};
|
|
46
|
-
}
|
|
47
|
-
.rdp-fab:active { cursor: grabbing; }
|
|
48
|
-
.rdp-fab-badge {
|
|
49
|
-
position: absolute; bottom: -3px; right: -3px; min-width: 18px; height: 18px;
|
|
50
|
-
padding: 0 5px; border-radius: 999px; background: var(--rdp-error); color: #fff;
|
|
51
|
-
font-size: 10px; font-weight: 700; display: grid; place-items: center;
|
|
52
|
-
border: 2px solid var(--rdp-bg);
|
|
53
|
+
function getRegisteredTools() {
|
|
54
|
+
return [...tools.values()];
|
|
53
55
|
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
.
|
|
57
|
-
position: fixed; background: var(--rdp-bg); border: 1px solid var(--rdp-border);
|
|
58
|
-
border-radius: var(--rdp-radius); box-shadow: var(--rdp-shadow); overflow: hidden;
|
|
59
|
-
display: flex; flex-direction: column; z-index: ${RDP_Z};
|
|
60
|
-
}
|
|
61
|
-
.rdp-menu { width: 320px; }
|
|
62
|
-
.rdp-panel { width: min(460px, calc(100vw - 32px)); max-height: min(78vh, 720px); }
|
|
63
|
-
|
|
64
|
-
.rdp-header {
|
|
65
|
-
display: flex; align-items: center; gap: 10px; padding: 10px 14px;
|
|
66
|
-
border-bottom: 1px solid var(--rdp-border); flex-shrink: 0;
|
|
56
|
+
function resolveTools(ids) {
|
|
57
|
+
if (!ids || ids.length === 0) return getRegisteredTools();
|
|
58
|
+
return ids.map((id) => tools.get(id)).filter((t) => Boolean(t));
|
|
67
59
|
}
|
|
68
|
-
|
|
69
|
-
|
|
60
|
+
function buildProtocolUrl(editor, loc) {
|
|
61
|
+
const line = loc.line ?? 1;
|
|
62
|
+
const col = loc.column ?? 1;
|
|
63
|
+
switch (editor) {
|
|
64
|
+
case "cursor":
|
|
65
|
+
return `cursor://file/${loc.file}:${line}:${col}`;
|
|
66
|
+
case "webstorm":
|
|
67
|
+
return `webstorm://open?file=${encodeURIComponent(loc.file)}&line=${line}&column=${col}`;
|
|
68
|
+
case "zed":
|
|
69
|
+
return `zed://file/${loc.file}:${line}:${col}`;
|
|
70
|
+
case "vscode":
|
|
71
|
+
case "auto":
|
|
72
|
+
default:
|
|
73
|
+
return `vscode://file/${loc.file}:${line}:${col}`;
|
|
74
|
+
}
|
|
70
75
|
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
76
|
+
var defaultOpenInEditor = async (loc, editor = "auto") => {
|
|
77
|
+
const url = buildProtocolUrl(editor, loc);
|
|
78
|
+
if (url && typeof window !== "undefined") {
|
|
79
|
+
try {
|
|
80
|
+
window.location.assign(url);
|
|
81
|
+
return true;
|
|
82
|
+
} catch {
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
if (typeof navigator !== "undefined" && navigator.clipboard) {
|
|
86
|
+
await navigator.clipboard.writeText(`${loc.file}${loc.line ? `:${loc.line}` : ""}`).catch(() => void 0);
|
|
87
|
+
}
|
|
88
|
+
return false;
|
|
89
|
+
};
|
|
90
|
+
var DevPanelContext = react.createContext(null);
|
|
91
|
+
function resolve(config) {
|
|
92
|
+
const enabled = config.enabled ?? (typeof process !== "undefined" ? process.env.NODE_ENV !== "production" : true);
|
|
93
|
+
return {
|
|
94
|
+
enabled,
|
|
95
|
+
editor: config.editor ?? "auto",
|
|
96
|
+
getRoute: config.getRoute ?? (() => typeof location !== "undefined" ? location.pathname : void 0),
|
|
97
|
+
openInEditor: config.openInEditor ?? defaultOpenInEditor,
|
|
98
|
+
graphEndpoint: config.graphEndpoint,
|
|
99
|
+
theme: config.theme ?? {},
|
|
100
|
+
tools: config.tools
|
|
101
|
+
};
|
|
80
102
|
}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
103
|
+
function DevPanelConfigProvider({
|
|
104
|
+
config,
|
|
105
|
+
children
|
|
106
|
+
}) {
|
|
107
|
+
const value = react.useMemo(() => resolve(config), [config]);
|
|
108
|
+
return /* @__PURE__ */ jsxRuntime.jsx(DevPanelContext.Provider, { value, children });
|
|
85
109
|
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
border-radius: 999px; font-size: 11px; font-weight: 700; line-height: 1;
|
|
91
|
-
}
|
|
92
|
-
.rdp-btn {
|
|
93
|
-
display: inline-flex; align-items: center; gap: 6px; padding: 5px 10px;
|
|
94
|
-
border-radius: 8px; border: 1px solid var(--rdp-border); background: transparent;
|
|
95
|
-
color: var(--rdp-text); font: inherit; font-size: 12px; cursor: pointer;
|
|
96
|
-
}
|
|
97
|
-
.rdp-btn:hover { background: rgba(255,255,255,0.05); }
|
|
98
|
-
.rdp-btn-primary {
|
|
99
|
-
background: var(--rdp-accent); color: var(--rdp-accent-contrast); border-color: transparent;
|
|
100
|
-
font-weight: 600; justify-content: center; width: 100%;
|
|
101
|
-
}
|
|
102
|
-
.rdp-btn-primary:hover { filter: brightness(1.08); }
|
|
103
|
-
.rdp-btn-sm { padding: 2px 7px; font-size: 11px; border-radius: 6px; }
|
|
104
|
-
.rdp-iconbtn {
|
|
105
|
-
display: grid; place-items: center; width: 28px; height: 28px; border-radius: 7px;
|
|
106
|
-
border: 1px solid var(--rdp-border); background: transparent; color: var(--rdp-text);
|
|
107
|
-
cursor: pointer;
|
|
108
|
-
}
|
|
109
|
-
.rdp-iconbtn:hover { background: rgba(255,255,255,0.06); }
|
|
110
|
-
.rdp-iconbtn-bare { border: none; width: 22px; height: 22px; color: var(--rdp-text-dim); }
|
|
111
|
-
.rdp-iconbtn-bare:hover { color: var(--rdp-text); background: rgba(255,255,255,0.06); }
|
|
112
|
-
|
|
113
|
-
.rdp-tabs { display: flex; gap: 4px; background: var(--rdp-bg-soft); padding: 3px; border-radius: 9px; }
|
|
114
|
-
.rdp-tab {
|
|
115
|
-
flex: 1; display: inline-flex; align-items: center; justify-content: center; gap: 5px;
|
|
116
|
-
padding: 6px 4px; border-radius: 7px; border: none; background: transparent;
|
|
117
|
-
color: var(--rdp-text-dim); font: inherit; font-size: 12px; cursor: pointer;
|
|
110
|
+
function useDevPanelConfig() {
|
|
111
|
+
const ctx = react.useContext(DevPanelContext);
|
|
112
|
+
if (!ctx) throw new Error("useDevPanelConfig must be used within <DevPanel> / DevPanelConfigProvider");
|
|
113
|
+
return ctx;
|
|
118
114
|
}
|
|
119
|
-
.rdp-tab[aria-selected="true"] { background: var(--rdp-bg-elev); color: var(--rdp-text); box-shadow: 0 1px 2px rgba(0,0,0,0.3); }
|
|
120
115
|
|
|
121
|
-
.
|
|
122
|
-
|
|
123
|
-
|
|
116
|
+
// src/tools/dev-logs/store.ts
|
|
117
|
+
var MAX_ENTRIES = 500;
|
|
118
|
+
var STORAGE_KEY = "react-dev-panel:dev-logs";
|
|
119
|
+
var entries = [];
|
|
120
|
+
var seq = 0;
|
|
121
|
+
var installed = false;
|
|
122
|
+
var hydrated = false;
|
|
123
|
+
var emitScheduled = false;
|
|
124
|
+
var persistTimer = null;
|
|
125
|
+
var listeners = /* @__PURE__ */ new Set();
|
|
126
|
+
var EMPTY = [];
|
|
127
|
+
function emit() {
|
|
128
|
+
if (emitScheduled) return;
|
|
129
|
+
emitScheduled = true;
|
|
130
|
+
const flush = () => {
|
|
131
|
+
emitScheduled = false;
|
|
132
|
+
listeners.forEach((listener) => listener());
|
|
133
|
+
};
|
|
134
|
+
if (typeof queueMicrotask === "function") queueMicrotask(flush);
|
|
135
|
+
else void Promise.resolve().then(flush);
|
|
136
|
+
}
|
|
137
|
+
function persist() {
|
|
138
|
+
if (typeof window === "undefined") return;
|
|
139
|
+
let list = entries;
|
|
140
|
+
for (let attempt = 0; attempt < 6; attempt += 1) {
|
|
141
|
+
try {
|
|
142
|
+
window.sessionStorage.setItem(STORAGE_KEY, JSON.stringify(list));
|
|
143
|
+
return;
|
|
144
|
+
} catch {
|
|
145
|
+
if (!list.length) return;
|
|
146
|
+
list = list.slice(0, Math.floor(list.length / 2));
|
|
147
|
+
}
|
|
148
|
+
}
|
|
124
149
|
}
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
150
|
+
function schedulePersist() {
|
|
151
|
+
if (typeof window === "undefined" || persistTimer) return;
|
|
152
|
+
persistTimer = setTimeout(() => {
|
|
153
|
+
persistTimer = null;
|
|
154
|
+
persist();
|
|
155
|
+
}, 500);
|
|
128
156
|
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
157
|
+
function hydrate() {
|
|
158
|
+
if (hydrated || typeof window === "undefined") return;
|
|
159
|
+
hydrated = true;
|
|
160
|
+
try {
|
|
161
|
+
const raw = window.sessionStorage.getItem(STORAGE_KEY);
|
|
162
|
+
if (!raw) return;
|
|
163
|
+
const parsed = JSON.parse(raw);
|
|
164
|
+
if (!Array.isArray(parsed)) return;
|
|
165
|
+
entries = parsed.slice(0, MAX_ENTRIES);
|
|
166
|
+
seq = entries.reduce((max, entry) => {
|
|
167
|
+
const n = Number(String(entry.id).replace("log-", ""));
|
|
168
|
+
return Number.isFinite(n) && n > max ? n : max;
|
|
169
|
+
}, 0);
|
|
170
|
+
emit();
|
|
171
|
+
} catch {
|
|
172
|
+
}
|
|
133
173
|
}
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
.rdp-overlay { position: fixed; inset: 0; pointer-events: none; z-index: ${RDP_Z - 1}; }
|
|
137
|
-
.rdp-hl {
|
|
138
|
-
position: fixed; border: 1px solid var(--rdp-accent); border-radius: 3px;
|
|
139
|
-
background: rgba(105,80,232,0.14); box-shadow: 0 0 0 1px rgba(105,80,232,0.4);
|
|
140
|
-
transition: all 60ms linear; pointer-events: none;
|
|
141
|
-
}
|
|
142
|
-
.rdp-tooltip {
|
|
143
|
-
position: fixed; max-width: 360px; padding: 8px 10px; border-radius: 9px;
|
|
144
|
-
background: rgba(15,18,24,0.86); backdrop-filter: blur(8px);
|
|
145
|
-
border: 1px solid rgba(255,255,255,0.12); box-shadow: var(--rdp-shadow); color: #fff;
|
|
146
|
-
pointer-events: none;
|
|
147
|
-
}
|
|
148
|
-
.rdp-toast {
|
|
149
|
-
position: fixed; bottom: 24px; left: 50%; transform: translateX(-50%);
|
|
150
|
-
padding: 7px 14px; border-radius: 9px; background: rgba(15,18,24,0.92);
|
|
151
|
-
border: 1px solid rgba(255,255,255,0.12); box-shadow: var(--rdp-shadow);
|
|
152
|
-
font-size: 12px; font-weight: 600; z-index: ${RDP_Z};
|
|
174
|
+
function getDevLogs() {
|
|
175
|
+
return entries;
|
|
153
176
|
}
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
.
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
function injectBaseStyles() {
|
|
167
|
-
if (injected || typeof document === "undefined") return;
|
|
168
|
-
if (document.getElementById(RDP_STYLE_ID)) {
|
|
169
|
-
injected = true;
|
|
170
|
-
return;
|
|
177
|
+
function getDevLogsServerSnapshot() {
|
|
178
|
+
return EMPTY;
|
|
179
|
+
}
|
|
180
|
+
function subscribeDevLogs(listener) {
|
|
181
|
+
listeners.add(listener);
|
|
182
|
+
return () => listeners.delete(listener);
|
|
183
|
+
}
|
|
184
|
+
function clearDevLogs() {
|
|
185
|
+
entries = [];
|
|
186
|
+
if (persistTimer) {
|
|
187
|
+
clearTimeout(persistTimer);
|
|
188
|
+
persistTimer = null;
|
|
171
189
|
}
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
}
|
|
178
|
-
function colorVar(key) {
|
|
179
|
-
switch (key) {
|
|
180
|
-
case "info":
|
|
181
|
-
return "var(--rdp-info)";
|
|
182
|
-
case "warning":
|
|
183
|
-
return "var(--rdp-warning)";
|
|
184
|
-
case "success":
|
|
185
|
-
return "var(--rdp-success)";
|
|
186
|
-
case "error":
|
|
187
|
-
return "var(--rdp-error)";
|
|
188
|
-
default:
|
|
189
|
-
return "var(--rdp-accent)";
|
|
190
|
+
if (typeof window !== "undefined") {
|
|
191
|
+
try {
|
|
192
|
+
window.sessionStorage.removeItem(STORAGE_KEY);
|
|
193
|
+
} catch {
|
|
194
|
+
}
|
|
190
195
|
}
|
|
196
|
+
emit();
|
|
191
197
|
}
|
|
192
|
-
function
|
|
193
|
-
return
|
|
198
|
+
function errorCount() {
|
|
199
|
+
return entries.reduce((n, e) => e.level === "error" ? n + 1 : n, 0);
|
|
194
200
|
}
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
201
|
+
function addDevLog(entry) {
|
|
202
|
+
seq += 1;
|
|
203
|
+
const next = {
|
|
204
|
+
...entry,
|
|
205
|
+
id: `log-${seq}`,
|
|
206
|
+
timestamp: Date.now(),
|
|
207
|
+
path: typeof window !== "undefined" ? window.location.pathname : void 0
|
|
208
|
+
};
|
|
209
|
+
entries = [next, ...entries].slice(0, MAX_ENTRIES);
|
|
210
|
+
emit();
|
|
211
|
+
schedulePersist();
|
|
200
212
|
}
|
|
201
|
-
function
|
|
202
|
-
|
|
213
|
+
function safeString(value) {
|
|
214
|
+
if (typeof value === "string") return value;
|
|
215
|
+
if (value instanceof Error) return value.message;
|
|
216
|
+
try {
|
|
217
|
+
return JSON.stringify(value);
|
|
218
|
+
} catch {
|
|
219
|
+
return String(value);
|
|
220
|
+
}
|
|
203
221
|
}
|
|
204
|
-
function
|
|
205
|
-
if (
|
|
206
|
-
|
|
222
|
+
function classifyApolloPayload(payload) {
|
|
223
|
+
if (payload && typeof payload === "object") {
|
|
224
|
+
const p = payload;
|
|
225
|
+
if (p.gqlErrors) return "server";
|
|
226
|
+
if (p.networkError || p.networkStatus) return "network";
|
|
227
|
+
}
|
|
228
|
+
return "server";
|
|
229
|
+
}
|
|
230
|
+
function captureConsole(level, args) {
|
|
231
|
+
const firstStr = typeof args[0] === "string" ? args[0] : safeString(args[0]);
|
|
232
|
+
if (firstStr.startsWith("[Apollo error]")) {
|
|
233
|
+
const payload = args[1];
|
|
234
|
+
addDevLog({
|
|
235
|
+
source: classifyApolloPayload(payload),
|
|
236
|
+
level,
|
|
237
|
+
message: firstStr.replace("[Apollo error] ", "").trim() || "Apollo error",
|
|
238
|
+
detail: payload !== void 0 ? safeString(payload) : void 0
|
|
239
|
+
});
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
const errorArg = args.find((a) => a instanceof Error);
|
|
243
|
+
addDevLog({
|
|
244
|
+
source: "client",
|
|
245
|
+
level,
|
|
246
|
+
message: args.map(safeString).join(" ").trim() || `console.${level}`,
|
|
247
|
+
stack: errorArg?.stack
|
|
248
|
+
});
|
|
207
249
|
}
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
250
|
+
var NETWORK_IGNORE = ["/_next/", "/__nextjs", "hot-update", "webpack", ".map", "/monitoring"];
|
|
251
|
+
function shouldIgnoreNetwork(url) {
|
|
252
|
+
return NETWORK_IGNORE.some((needle) => url.includes(needle));
|
|
253
|
+
}
|
|
254
|
+
function resolveRequest(input) {
|
|
255
|
+
if (typeof input === "string") return { url: input, method: "GET" };
|
|
256
|
+
if (input instanceof URL) return { url: input.href, method: "GET" };
|
|
257
|
+
return { url: input.url, method: input.method || "GET" };
|
|
258
|
+
}
|
|
259
|
+
function graphqlOperationName(body) {
|
|
260
|
+
if (typeof body !== "string") return void 0;
|
|
261
|
+
try {
|
|
262
|
+
const parsed = JSON.parse(body);
|
|
263
|
+
if (Array.isArray(parsed)) {
|
|
264
|
+
const names = parsed.map((p) => p?.operationName).filter(Boolean);
|
|
265
|
+
return names.length ? names.join(", ") : void 0;
|
|
222
266
|
}
|
|
223
|
-
|
|
267
|
+
return parsed?.operationName || void 0;
|
|
268
|
+
} catch {
|
|
269
|
+
return void 0;
|
|
270
|
+
}
|
|
224
271
|
}
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
var IconGraph = ({ size }) => /* @__PURE__ */ jsxRuntime.jsxs(Svg, { size, children: [
|
|
235
|
-
/* @__PURE__ */ jsxRuntime.jsx("rect", { x: "3", y: "3", width: "7", height: "7", rx: "1.5" }),
|
|
236
|
-
/* @__PURE__ */ jsxRuntime.jsx("rect", { x: "14", y: "14", width: "7", height: "7", rx: "1.5" }),
|
|
237
|
-
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M10 6.5h4a3 3 0 0 1 3 3V14" })
|
|
238
|
-
] });
|
|
239
|
-
var IconX = ({ size }) => /* @__PURE__ */ jsxRuntime.jsx(Svg, { size, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M6 6l12 12M18 6L6 18" }) });
|
|
240
|
-
var IconChevronRight = ({ size }) => /* @__PURE__ */ jsxRuntime.jsx(Svg, { size, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M9 6l6 6-6 6" }) });
|
|
241
|
-
var IconChevronDown = ({ size }) => /* @__PURE__ */ jsxRuntime.jsx(Svg, { size, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M6 9l6 6 6-6" }) });
|
|
242
|
-
var IconSearch = ({ size }) => /* @__PURE__ */ jsxRuntime.jsxs(Svg, { size, children: [
|
|
243
|
-
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "11", cy: "11", r: "7" }),
|
|
244
|
-
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M21 21l-4-4" })
|
|
245
|
-
] });
|
|
246
|
-
var IconCopy = ({ size }) => /* @__PURE__ */ jsxRuntime.jsxs(Svg, { size, children: [
|
|
247
|
-
/* @__PURE__ */ jsxRuntime.jsx("rect", { x: "9", y: "9", width: "11", height: "11", rx: "2" }),
|
|
248
|
-
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M5 15V5a2 2 0 0 1 2-2h10" })
|
|
249
|
-
] });
|
|
250
|
-
var IconFileCode = ({ size }) => /* @__PURE__ */ jsxRuntime.jsxs(Svg, { size, children: [
|
|
251
|
-
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M14 3H7a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V8z" }),
|
|
252
|
-
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M14 3v5h5M10 12l-2 2 2 2M14 12l2 2-2 2" })
|
|
253
|
-
] });
|
|
254
|
-
var IconRefresh = ({ size }) => /* @__PURE__ */ jsxRuntime.jsxs(Svg, { size, children: [
|
|
255
|
-
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M21 12a9 9 0 1 1-3-6.7L21 8" }),
|
|
256
|
-
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M21 3v5h-5" })
|
|
257
|
-
] });
|
|
258
|
-
var IconPointer = ({ size }) => /* @__PURE__ */ jsxRuntime.jsx(Svg, { size, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M5 3l16 7-7 2-2 7z" }) });
|
|
259
|
-
var IconLayers = ({ size }) => /* @__PURE__ */ jsxRuntime.jsx(Svg, { size, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 3l9 5-9 5-9-5 9-5zM3 13l9 5 9-5" }) });
|
|
260
|
-
var IconArrowUp = ({ size }) => /* @__PURE__ */ jsxRuntime.jsx(Svg, { size, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 19V5M6 11l6-6 6 6" }) });
|
|
261
|
-
var buffer = [];
|
|
262
|
-
var nextId = 1;
|
|
263
|
-
var listeners = /* @__PURE__ */ new Set();
|
|
264
|
-
function emit() {
|
|
265
|
-
listeners.forEach((l) => l());
|
|
272
|
+
function detectOpType(query, opName) {
|
|
273
|
+
if (typeof query !== "string") return void 0;
|
|
274
|
+
if (opName) {
|
|
275
|
+
const named = new RegExp(`\\b(query|mutation|subscription)\\s+${opName}\\b`).exec(query);
|
|
276
|
+
if (named) return named[1];
|
|
277
|
+
}
|
|
278
|
+
const keyword = /\b(query|mutation|subscription)\b/.exec(query);
|
|
279
|
+
if (keyword) return keyword[1];
|
|
280
|
+
return /^\s*\{/.test(query) ? "query" : void 0;
|
|
266
281
|
}
|
|
267
|
-
function
|
|
268
|
-
|
|
269
|
-
|
|
282
|
+
function graphqlOperationType(body) {
|
|
283
|
+
if (typeof body !== "string") return void 0;
|
|
284
|
+
try {
|
|
285
|
+
const parsed = JSON.parse(body);
|
|
286
|
+
const ops = Array.isArray(parsed) ? parsed : [parsed];
|
|
287
|
+
const types = ops.map((p) => detectOpType(p?.query, p?.operationName)).filter(Boolean);
|
|
288
|
+
const unique = Array.from(new Set(types));
|
|
289
|
+
return unique.length === 1 ? unique[0] : void 0;
|
|
290
|
+
} catch {
|
|
291
|
+
return void 0;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
function collapseSignedQuery(u) {
|
|
295
|
+
return u.searchParams.has("X-Amz-Signature") ? "?[signed]" : u.search;
|
|
296
|
+
}
|
|
297
|
+
function shortUrl(url) {
|
|
298
|
+
try {
|
|
299
|
+
const u = new URL(url, window.location.origin);
|
|
300
|
+
return u.pathname + collapseSignedQuery(u);
|
|
301
|
+
} catch {
|
|
302
|
+
return url;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
function redactedUrl(url) {
|
|
306
|
+
try {
|
|
307
|
+
const u = new URL(url, window.location.origin);
|
|
308
|
+
return `${u.origin}${u.pathname}${collapseSignedQuery(u)}`;
|
|
309
|
+
} catch {
|
|
310
|
+
return url;
|
|
311
|
+
}
|
|
270
312
|
}
|
|
271
|
-
function
|
|
272
|
-
|
|
273
|
-
|
|
313
|
+
function networkLevel(status) {
|
|
314
|
+
if (status === 0 || status >= 500) return "error";
|
|
315
|
+
if (status >= 400) return "warn";
|
|
316
|
+
return "info";
|
|
317
|
+
}
|
|
318
|
+
var MAX_REASON_CHARS = 160;
|
|
319
|
+
function errorReason(body) {
|
|
320
|
+
if (!body) return void 0;
|
|
321
|
+
const text = body.trim();
|
|
322
|
+
if (!text) return void 0;
|
|
323
|
+
const xmlCode = /<Code>([^<]+)<\/Code>/i.exec(text)?.[1];
|
|
324
|
+
const xmlMessage = /<Message>([^<]+)<\/Message>/i.exec(text)?.[1];
|
|
325
|
+
if (xmlCode || xmlMessage) return [xmlCode, xmlMessage].filter(Boolean).join(": ").slice(0, MAX_REASON_CHARS);
|
|
326
|
+
if (text[0] === "{" || text[0] === "[") {
|
|
274
327
|
try {
|
|
275
|
-
|
|
328
|
+
const parsed = JSON.parse(text);
|
|
329
|
+
const gql = parsed?.errors?.map((e) => e?.message).filter(Boolean).join("; ");
|
|
330
|
+
const reason = gql || (typeof parsed.message === "string" ? parsed.message : void 0) || (typeof parsed.error === "string" ? parsed.error : void 0);
|
|
331
|
+
if (reason) return reason.slice(0, MAX_REASON_CHARS);
|
|
276
332
|
} catch {
|
|
277
|
-
return String(a);
|
|
278
333
|
}
|
|
279
|
-
}
|
|
334
|
+
}
|
|
335
|
+
const firstLine = text.split("\n").find((line) => line.trim());
|
|
336
|
+
return firstLine ? firstLine.slice(0, MAX_REASON_CHARS) : void 0;
|
|
280
337
|
}
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
const
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
const res = await orig(input, init);
|
|
300
|
-
push(res.ok ? "network" : "error", `${method} ${url}`, `${res.status} \xB7 ${Date.now() - start}ms`);
|
|
301
|
-
return res;
|
|
302
|
-
} catch (err) {
|
|
303
|
-
push("error", `${method} ${url}`, `failed \xB7 ${String(err)}`);
|
|
304
|
-
throw err;
|
|
305
|
-
}
|
|
306
|
-
};
|
|
338
|
+
function graphqlResponseErrors(body) {
|
|
339
|
+
if (!body) return void 0;
|
|
340
|
+
const trimmed = body.trim();
|
|
341
|
+
if (trimmed[0] !== "{" && trimmed[0] !== "[") return void 0;
|
|
342
|
+
try {
|
|
343
|
+
const parsed = JSON.parse(trimmed);
|
|
344
|
+
const result = Array.isArray(parsed) ? parsed[0] : parsed;
|
|
345
|
+
const errors = result?.errors;
|
|
346
|
+
if (!Array.isArray(errors) || errors.length === 0) return void 0;
|
|
347
|
+
const reason = errors.map((e) => {
|
|
348
|
+
const code = e?.extensions?.code;
|
|
349
|
+
return code ? `${code}: ${e?.message ?? ""}`.trim() : e?.message;
|
|
350
|
+
}).filter(Boolean).join("; ").slice(0, MAX_REASON_CHARS) || "GraphQL error";
|
|
351
|
+
const data = result?.data;
|
|
352
|
+
const partial = data != null && typeof data === "object" && Object.values(data).some((v) => v != null);
|
|
353
|
+
return { reason, partial };
|
|
354
|
+
} catch {
|
|
355
|
+
return void 0;
|
|
307
356
|
}
|
|
308
357
|
}
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
358
|
+
var MAX_BODY_CHARS = 5e4;
|
|
359
|
+
function truncateBody(text) {
|
|
360
|
+
if (text.length <= MAX_BODY_CHARS) return text;
|
|
361
|
+
return `${text.slice(0, MAX_BODY_CHARS)}
|
|
362
|
+
\u2026 [truncated ${text.length - MAX_BODY_CHARS} chars]`;
|
|
312
363
|
}
|
|
313
|
-
function
|
|
314
|
-
|
|
364
|
+
function prettyMaybeJson(text) {
|
|
365
|
+
const trimmed = text.trim();
|
|
366
|
+
if (trimmed[0] !== "{" && trimmed[0] !== "[") return text;
|
|
367
|
+
try {
|
|
368
|
+
return JSON.stringify(JSON.parse(trimmed), null, 2);
|
|
369
|
+
} catch {
|
|
370
|
+
return text;
|
|
371
|
+
}
|
|
315
372
|
}
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
return
|
|
373
|
+
function formatGraphqlBody(parsed) {
|
|
374
|
+
const ops = Array.isArray(parsed) ? parsed : [parsed];
|
|
375
|
+
if (!ops.length || !ops.every((op) => op && typeof op === "object" && typeof op.query === "string")) return null;
|
|
376
|
+
return ops.map((op) => {
|
|
377
|
+
const parts = [];
|
|
378
|
+
if (op.operationName) parts.push(`# Operation: ${op.operationName}`);
|
|
379
|
+
if (op.variables && Object.keys(op.variables).length > 0)
|
|
380
|
+
parts.push(`# Variables
|
|
381
|
+
${JSON.stringify(op.variables, null, 2)}`);
|
|
382
|
+
parts.push(`# Query
|
|
383
|
+
${op.query.trim()}`);
|
|
384
|
+
return parts.join("\n\n");
|
|
385
|
+
}).join("\n\n\u2014\u2014\u2014\n\n");
|
|
386
|
+
}
|
|
387
|
+
function formatBodyString(text) {
|
|
388
|
+
const trimmed = text.trim();
|
|
389
|
+
if (trimmed[0] === "{" || trimmed[0] === "[") {
|
|
390
|
+
try {
|
|
391
|
+
const parsed = JSON.parse(trimmed);
|
|
392
|
+
return formatGraphqlBody(parsed) ?? JSON.stringify(parsed, null, 2);
|
|
393
|
+
} catch {
|
|
394
|
+
return text;
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
return text;
|
|
398
|
+
}
|
|
399
|
+
var SENSITIVE_HEADERS = ["authorization", "cookie", "set-cookie", "x-api-key", "proxy-authorization"];
|
|
400
|
+
function formatHeaders(source) {
|
|
401
|
+
const lines = [];
|
|
402
|
+
source.forEach((value, key) => {
|
|
403
|
+
const redacted = SENSITIVE_HEADERS.includes(key.toLowerCase()) ? "[redacted]" : value;
|
|
404
|
+
lines.push(`${key}: ${redacted}`);
|
|
405
|
+
});
|
|
406
|
+
return lines.length ? lines.join("\n") : void 0;
|
|
407
|
+
}
|
|
408
|
+
function requestHeaders(input, init) {
|
|
409
|
+
const merged = new Headers();
|
|
410
|
+
if (input instanceof Request) input.headers.forEach((value, key) => merged.set(key, value));
|
|
411
|
+
if (init?.headers) new Headers(init.headers).forEach((value, key) => merged.set(key, value));
|
|
412
|
+
return formatHeaders(merged);
|
|
413
|
+
}
|
|
414
|
+
function rawRequestBody(body) {
|
|
415
|
+
if (typeof body !== "string") return void 0;
|
|
416
|
+
return truncateBody(body);
|
|
417
|
+
}
|
|
418
|
+
function readableRequestBody(body) {
|
|
419
|
+
if (body == null) return void 0;
|
|
420
|
+
if (typeof body === "string") return truncateBody(formatBodyString(body));
|
|
421
|
+
if (body instanceof URLSearchParams) return body.toString();
|
|
422
|
+
const name = body.constructor?.name;
|
|
423
|
+
return `[${name || "binary"} body \u2014 not shown]`;
|
|
424
|
+
}
|
|
425
|
+
async function readResponseBody(res) {
|
|
426
|
+
try {
|
|
427
|
+
const ct = res.headers.get("content-type") ?? "";
|
|
428
|
+
if (ct && !/json|text|xml|graphql|javascript|csv|html/i.test(ct)) return `[${ct} response \u2014 not shown]`;
|
|
429
|
+
const text = await res.text();
|
|
430
|
+
if (!text) return void 0;
|
|
431
|
+
return truncateBody(prettyMaybeJson(text));
|
|
432
|
+
} catch {
|
|
433
|
+
return void 0;
|
|
434
|
+
}
|
|
319
435
|
}
|
|
320
|
-
function
|
|
321
|
-
|
|
322
|
-
|
|
436
|
+
function captureFetch() {
|
|
437
|
+
if (typeof window.fetch !== "function") return;
|
|
438
|
+
const origFetch = window.fetch.bind(window);
|
|
439
|
+
window.fetch = async (input, init) => {
|
|
440
|
+
const { url, method: inferredMethod } = resolveRequest(input);
|
|
441
|
+
const method = (init?.method || inferredMethod || "GET").toUpperCase();
|
|
442
|
+
if (shouldIgnoreNetwork(url)) return origFetch(input, init);
|
|
443
|
+
const opName = graphqlOperationName(init?.body ?? null);
|
|
444
|
+
const opType = graphqlOperationType(init?.body ?? null);
|
|
445
|
+
const reqHeaders = requestHeaders(input, init);
|
|
446
|
+
const requestBody = readableRequestBody(init?.body ?? null);
|
|
447
|
+
const requestBodyRaw = rawRequestBody(init?.body ?? null);
|
|
448
|
+
const start = Date.now();
|
|
449
|
+
const log = (status, statusText, errored, responseBody, responseHeaders) => {
|
|
450
|
+
const ms = Date.now() - start;
|
|
451
|
+
const opLabel = opName ? `${opType ? `${opType} ` : ""}${opName}` : void 0;
|
|
452
|
+
const label = opLabel ? `${shortUrl(url)} \xB7 ${opLabel}` : shortUrl(url);
|
|
453
|
+
const gqlErrors = !errored && status < 400 ? graphqlResponseErrors(responseBody) : void 0;
|
|
454
|
+
const statusLabel = errored ? "FAILED" : String(status);
|
|
455
|
+
const reason = errored ? statusText : status >= 400 ? errorReason(responseBody) : gqlErrors?.reason;
|
|
456
|
+
const level = errored ? "error" : gqlErrors ? gqlErrors.partial ? "warn" : "error" : networkLevel(status);
|
|
457
|
+
addDevLog({
|
|
458
|
+
source: "network",
|
|
459
|
+
level,
|
|
460
|
+
message: `${method} ${statusLabel} ${label} (${ms}ms)${reason ? ` \u2014 ${reason}` : ""}`,
|
|
461
|
+
detail: `${method} ${redactedUrl(url)}
|
|
462
|
+
${errored ? statusText : `${status} ${statusText}`} \xB7 ${ms}ms${gqlErrors ? ` \xB7 GraphQL ${gqlErrors.partial ? "partial error" : "error"}` : ""}`,
|
|
463
|
+
requestHeaders: reqHeaders,
|
|
464
|
+
requestBody,
|
|
465
|
+
requestBodyRaw,
|
|
466
|
+
responseHeaders,
|
|
467
|
+
responseBody
|
|
468
|
+
});
|
|
469
|
+
};
|
|
470
|
+
try {
|
|
471
|
+
const res = await origFetch(input, init);
|
|
472
|
+
let clone = null;
|
|
473
|
+
try {
|
|
474
|
+
clone = res.clone();
|
|
475
|
+
} catch {
|
|
476
|
+
clone = null;
|
|
477
|
+
}
|
|
478
|
+
const resHeaders = formatHeaders(res.headers);
|
|
479
|
+
if (clone) void readResponseBody(clone).then((body) => log(res.status, res.statusText, false, body, resHeaders));
|
|
480
|
+
else log(res.status, res.statusText, false, void 0, resHeaders);
|
|
481
|
+
return res;
|
|
482
|
+
} catch (err) {
|
|
483
|
+
log(0, err instanceof Error ? err.message : "Network error", true);
|
|
484
|
+
throw err;
|
|
485
|
+
}
|
|
486
|
+
};
|
|
323
487
|
}
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
488
|
+
function installDevLogCapture() {
|
|
489
|
+
if (installed || typeof window === "undefined") return;
|
|
490
|
+
installed = true;
|
|
491
|
+
hydrate();
|
|
492
|
+
captureFetch();
|
|
493
|
+
window.addEventListener("pagehide", persist);
|
|
494
|
+
const origError = console.error.bind(console);
|
|
495
|
+
const origWarn = console.warn.bind(console);
|
|
496
|
+
const origLog = console.log.bind(console);
|
|
497
|
+
console.error = (...args) => {
|
|
498
|
+
origError(...args);
|
|
499
|
+
try {
|
|
500
|
+
captureConsole("error", args);
|
|
501
|
+
} catch {
|
|
502
|
+
}
|
|
503
|
+
};
|
|
504
|
+
console.warn = (...args) => {
|
|
505
|
+
origWarn(...args);
|
|
506
|
+
try {
|
|
507
|
+
captureConsole("warn", args);
|
|
508
|
+
} catch {
|
|
509
|
+
}
|
|
510
|
+
};
|
|
511
|
+
console.log = (...args) => {
|
|
512
|
+
origLog(...args);
|
|
513
|
+
try {
|
|
514
|
+
captureConsole("info", args);
|
|
515
|
+
} catch {
|
|
516
|
+
}
|
|
517
|
+
};
|
|
518
|
+
window.addEventListener("error", (event) => {
|
|
519
|
+
addDevLog({
|
|
520
|
+
source: "client",
|
|
521
|
+
level: "error",
|
|
522
|
+
message: event.message || "Uncaught error",
|
|
523
|
+
stack: event.error?.stack,
|
|
524
|
+
detail: event.filename ? `${event.filename}:${event.lineno}:${event.colno}` : void 0
|
|
525
|
+
});
|
|
526
|
+
});
|
|
527
|
+
window.addEventListener("unhandledrejection", (event) => {
|
|
528
|
+
const reason = event.reason;
|
|
529
|
+
addDevLog({
|
|
530
|
+
source: "client",
|
|
531
|
+
level: "error",
|
|
532
|
+
message: reason?.message ? `Unhandled rejection: ${reason.message}` : "Unhandled promise rejection",
|
|
533
|
+
stack: reason?.stack,
|
|
534
|
+
detail: safeString(event.reason)
|
|
535
|
+
});
|
|
536
|
+
});
|
|
537
|
+
}
|
|
538
|
+
var SOURCE_COLOR = {
|
|
539
|
+
server: "warning",
|
|
540
|
+
client: "info",
|
|
541
|
+
network: "success"
|
|
331
542
|
};
|
|
332
|
-
function
|
|
333
|
-
const
|
|
334
|
-
const
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
543
|
+
function formatTime(ts) {
|
|
544
|
+
const d = new Date(ts);
|
|
545
|
+
const pad = (n) => String(n).padStart(2, "0");
|
|
546
|
+
return `${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;
|
|
547
|
+
}
|
|
548
|
+
function buildSections(entry) {
|
|
549
|
+
const sections = [];
|
|
550
|
+
const requestTabs = [];
|
|
551
|
+
if (entry.requestBody) {
|
|
552
|
+
const hasRaw = Boolean(entry.requestBodyRaw && entry.requestBodyRaw !== entry.requestBody);
|
|
553
|
+
requestTabs.push({
|
|
554
|
+
key: "payload",
|
|
555
|
+
label: "Payload",
|
|
556
|
+
value: entry.requestBody,
|
|
557
|
+
variants: hasRaw ? [
|
|
558
|
+
{ key: "pretty", label: "Pretty", value: entry.requestBody },
|
|
559
|
+
{ key: "raw", label: "Raw", value: entry.requestBodyRaw }
|
|
560
|
+
] : void 0
|
|
561
|
+
});
|
|
562
|
+
}
|
|
563
|
+
if (entry.requestHeaders) requestTabs.push({ key: "headers", label: "Headers", value: entry.requestHeaders });
|
|
564
|
+
if (requestTabs.length) sections.push({ label: "Request", tabs: requestTabs });
|
|
565
|
+
const responseTabs = [];
|
|
566
|
+
if (entry.responseBody) responseTabs.push({ key: "body", label: "Body", value: entry.responseBody });
|
|
567
|
+
if (entry.responseHeaders) responseTabs.push({ key: "headers", label: "Headers", value: entry.responseHeaders });
|
|
568
|
+
if (responseTabs.length) sections.push({ label: "Response", tabs: responseTabs });
|
|
569
|
+
if (entry.stack) sections.push({ label: "Stack trace", tabs: [{ key: "stack", label: "Stack trace", value: entry.stack }] });
|
|
570
|
+
if (!sections.length && entry.detail) sections.push({ label: "Detail", tabs: [{ key: "detail", label: "Detail", value: entry.detail }] });
|
|
571
|
+
return sections;
|
|
572
|
+
}
|
|
573
|
+
var TOGGLE_SX = {
|
|
574
|
+
"& .MuiToggleButton-root": {
|
|
575
|
+
py: 0,
|
|
576
|
+
px: 0.75,
|
|
577
|
+
height: 20,
|
|
578
|
+
fontSize: "0.6rem",
|
|
579
|
+
fontWeight: 700,
|
|
580
|
+
lineHeight: 1,
|
|
581
|
+
letterSpacing: 0.3,
|
|
582
|
+
textTransform: "uppercase",
|
|
583
|
+
border: "1px solid",
|
|
584
|
+
borderColor: "divider"
|
|
585
|
+
}
|
|
586
|
+
};
|
|
587
|
+
function CopyButton({ value }) {
|
|
588
|
+
const [copied, setCopied] = react.useState(false);
|
|
589
|
+
const handleCopy = react.useCallback(
|
|
590
|
+
(e) => {
|
|
591
|
+
e.stopPropagation();
|
|
592
|
+
navigator.clipboard?.writeText(value).then(
|
|
593
|
+
() => {
|
|
594
|
+
setCopied(true);
|
|
595
|
+
window.setTimeout(() => setCopied(false), 1200);
|
|
596
|
+
},
|
|
597
|
+
() => void 0
|
|
598
|
+
);
|
|
599
|
+
},
|
|
600
|
+
[value]
|
|
601
|
+
);
|
|
602
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Tooltip2__default.default, { title: copied ? "Copied" : "Copy", placement: "top", children: /* @__PURE__ */ jsxRuntime.jsx(IconButton__default.default, { size: "small", onClick: handleCopy, sx: { color: copied ? "success.main" : void 0 }, children: copied ? /* @__PURE__ */ jsxRuntime.jsx(lu.LuCheck, { size: 13 }) : /* @__PURE__ */ jsxRuntime.jsx(lu.LuCopy, { size: 13 }) }) });
|
|
603
|
+
}
|
|
604
|
+
function SectionBlock({ section }) {
|
|
605
|
+
const theme = styles.useTheme();
|
|
606
|
+
const [activeTabKey, setActiveTabKey] = react.useState(section.tabs[0]?.key);
|
|
607
|
+
const [variantByTab, setVariantByTab] = react.useState({});
|
|
608
|
+
const activeTab = section.tabs.find((t) => t.key === activeTabKey) ?? section.tabs[0];
|
|
609
|
+
const activeVariantKey = variantByTab[activeTab.key] ?? activeTab.variants?.[0]?.key;
|
|
610
|
+
const activeVariant = activeTab.variants?.find((v) => v.key === activeVariantKey);
|
|
611
|
+
const displayValue = activeVariant?.value ?? activeTab.value;
|
|
612
|
+
const showTabs = section.tabs.length > 1;
|
|
613
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(Box6__default.default, { children: [
|
|
614
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Stack__default.default, { direction: "row", alignItems: "center", justifyContent: "space-between", sx: { px: 1, py: 0.25, gap: 0.5, flexWrap: "wrap" }, children: [
|
|
615
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Stack__default.default, { direction: "row", alignItems: "center", spacing: 0.75, sx: { minWidth: 0 }, children: [
|
|
616
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography__default.default, { variant: "caption", sx: { color: "text.disabled", fontWeight: 700, textTransform: "uppercase", letterSpacing: 0.4 }, children: section.label }),
|
|
617
|
+
showTabs && /* @__PURE__ */ jsxRuntime.jsx(ToggleButtonGroup__default.default, { size: "small", exclusive: true, value: activeTab.key, onChange: (_, next) => next && setActiveTabKey(next), sx: TOGGLE_SX, children: section.tabs.map((t) => /* @__PURE__ */ jsxRuntime.jsx(ToggleButton__default.default, { value: t.key, children: t.label }, t.key)) })
|
|
618
|
+
] }),
|
|
619
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Stack__default.default, { direction: "row", alignItems: "center", spacing: 0.5, children: [
|
|
620
|
+
activeTab.variants && /* @__PURE__ */ jsxRuntime.jsx(
|
|
621
|
+
ToggleButtonGroup__default.default,
|
|
622
|
+
{
|
|
623
|
+
size: "small",
|
|
624
|
+
exclusive: true,
|
|
625
|
+
value: activeVariantKey,
|
|
626
|
+
onChange: (_, next) => next && setVariantByTab((prev) => ({ ...prev, [activeTab.key]: next })),
|
|
627
|
+
sx: TOGGLE_SX,
|
|
628
|
+
children: activeTab.variants.map((v) => /* @__PURE__ */ jsxRuntime.jsx(ToggleButton__default.default, { value: v.key, children: v.label }, v.key))
|
|
629
|
+
}
|
|
630
|
+
),
|
|
631
|
+
/* @__PURE__ */ jsxRuntime.jsx(CopyButton, { value: displayValue })
|
|
632
|
+
] })
|
|
342
633
|
] }),
|
|
343
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
344
|
-
|
|
634
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
635
|
+
Box6__default.default,
|
|
345
636
|
{
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
637
|
+
component: "pre",
|
|
638
|
+
sx: {
|
|
639
|
+
m: 0,
|
|
640
|
+
px: 1,
|
|
641
|
+
pb: 1,
|
|
642
|
+
fontFamily: "monospace",
|
|
643
|
+
fontSize: "0.7rem",
|
|
644
|
+
color: "text.secondary",
|
|
645
|
+
whiteSpace: "pre-wrap",
|
|
646
|
+
wordBreak: "break-word",
|
|
647
|
+
overflowX: "auto",
|
|
648
|
+
maxHeight: 280,
|
|
649
|
+
bgcolor: styles.alpha(theme.palette.grey[500], 0.06)
|
|
650
|
+
},
|
|
651
|
+
children: displayValue
|
|
652
|
+
}
|
|
653
|
+
)
|
|
359
654
|
] });
|
|
360
655
|
}
|
|
656
|
+
function LogRow({ entry, showPath }) {
|
|
657
|
+
const [open, setOpen] = react.useState(false);
|
|
658
|
+
const sections = react.useMemo(() => buildSections(entry), [entry]);
|
|
659
|
+
const expandable = sections.length > 0;
|
|
660
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(Box6__default.default, { sx: { border: "1px solid", borderColor: "divider", borderRadius: 1, overflow: "hidden" }, children: [
|
|
661
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
662
|
+
Box6__default.default,
|
|
663
|
+
{
|
|
664
|
+
onClick: expandable ? () => setOpen((v) => !v) : void 0,
|
|
665
|
+
sx: {
|
|
666
|
+
display: "flex",
|
|
667
|
+
alignItems: "flex-start",
|
|
668
|
+
gap: 1,
|
|
669
|
+
px: 1,
|
|
670
|
+
py: 0.75,
|
|
671
|
+
cursor: expandable ? "pointer" : "default",
|
|
672
|
+
"&:hover": expandable ? { bgcolor: "action.hover" } : void 0
|
|
673
|
+
},
|
|
674
|
+
children: [
|
|
675
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
676
|
+
Chip__default.default,
|
|
677
|
+
{
|
|
678
|
+
label: entry.source,
|
|
679
|
+
size: "small",
|
|
680
|
+
color: SOURCE_COLOR[entry.source],
|
|
681
|
+
variant: "soft",
|
|
682
|
+
sx: { height: 18, fontSize: "0.6rem", textTransform: "uppercase", fontWeight: 700, mt: 0.25, flexShrink: 0 }
|
|
683
|
+
}
|
|
684
|
+
),
|
|
685
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Box6__default.default, { sx: { flex: 1, minWidth: 0 }, children: [
|
|
686
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
687
|
+
Typography__default.default,
|
|
688
|
+
{
|
|
689
|
+
variant: "body2",
|
|
690
|
+
sx: {
|
|
691
|
+
fontFamily: "monospace",
|
|
692
|
+
fontSize: "0.75rem",
|
|
693
|
+
color: entry.level === "error" ? "error.main" : "text.primary",
|
|
694
|
+
wordBreak: "break-word",
|
|
695
|
+
whiteSpace: "pre-wrap"
|
|
696
|
+
},
|
|
697
|
+
children: entry.message
|
|
698
|
+
}
|
|
699
|
+
),
|
|
700
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Stack__default.default, { direction: "row", spacing: 1, sx: { mt: 0.25 }, children: [
|
|
701
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography__default.default, { variant: "caption", sx: { color: "text.disabled", fontFamily: "monospace" }, children: formatTime(entry.timestamp) }),
|
|
702
|
+
showPath && entry.path && /* @__PURE__ */ jsxRuntime.jsx(Typography__default.default, { variant: "caption", sx: { color: "text.disabled", fontFamily: "monospace", wordBreak: "break-all" }, children: entry.path })
|
|
703
|
+
] })
|
|
704
|
+
] }),
|
|
705
|
+
expandable && /* @__PURE__ */ jsxRuntime.jsx(Box6__default.default, { sx: { flexShrink: 0, color: "text.disabled", transform: open ? "rotate(180deg)" : "none", transition: "transform 0.15s", mt: 0.25 }, children: /* @__PURE__ */ jsxRuntime.jsx(lu.LuChevronDown, { size: 14 }) })
|
|
706
|
+
]
|
|
707
|
+
}
|
|
708
|
+
),
|
|
709
|
+
expandable && /* @__PURE__ */ jsxRuntime.jsx(Collapse__default.default, { in: open, unmountOnExit: true, children: /* @__PURE__ */ jsxRuntime.jsx(Stack__default.default, { spacing: 0.5, sx: { borderTop: "1px solid", borderColor: "divider", py: 0.5 }, children: sections.map((section) => /* @__PURE__ */ jsxRuntime.jsx(SectionBlock, { section }, section.label)) }) })
|
|
710
|
+
] });
|
|
711
|
+
}
|
|
712
|
+
function DevLogsPanel({ onClose }) {
|
|
713
|
+
const logs = react.useSyncExternalStore(subscribeDevLogs, getDevLogs, getDevLogsServerSnapshot);
|
|
714
|
+
const pathname = useDevPanelConfig().getRoute();
|
|
715
|
+
const [source, setSource] = react.useState("all");
|
|
716
|
+
const [level, setLevel] = react.useState("all");
|
|
717
|
+
const [thisPageOnly, setThisPageOnly] = react.useState(true);
|
|
718
|
+
const [search, setSearch2] = react.useState("");
|
|
719
|
+
const filtered = react.useMemo(() => {
|
|
720
|
+
const term = search.trim().toLowerCase();
|
|
721
|
+
return logs.filter((entry) => {
|
|
722
|
+
if (source !== "all" && entry.source !== source) return false;
|
|
723
|
+
if (level !== "all" && entry.level !== level) return false;
|
|
724
|
+
if (thisPageOnly && entry.path && entry.path !== pathname) return false;
|
|
725
|
+
if (term) {
|
|
726
|
+
const haystack = `${entry.message} ${entry.detail ?? ""} ${entry.stack ?? ""}`.toLowerCase();
|
|
727
|
+
if (!haystack.includes(term)) return false;
|
|
728
|
+
}
|
|
729
|
+
return true;
|
|
730
|
+
});
|
|
731
|
+
}, [logs, source, level, thisPageOnly, search, pathname]);
|
|
732
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
733
|
+
Box6__default.default,
|
|
734
|
+
{
|
|
735
|
+
"data-rdp-ignore": "",
|
|
736
|
+
sx: {
|
|
737
|
+
position: "fixed",
|
|
738
|
+
bottom: 96,
|
|
739
|
+
right: 24,
|
|
740
|
+
zIndex: (t) => t.zIndex.modal + 1,
|
|
741
|
+
width: "min(460px, calc(100vw - 32px))",
|
|
742
|
+
maxHeight: "min(70vh, 640px)",
|
|
743
|
+
display: "flex",
|
|
744
|
+
flexDirection: "column",
|
|
745
|
+
borderRadius: 2,
|
|
746
|
+
overflow: "hidden",
|
|
747
|
+
border: "1px solid",
|
|
748
|
+
borderColor: "divider",
|
|
749
|
+
bgcolor: "background.paper",
|
|
750
|
+
boxShadow: 12
|
|
751
|
+
},
|
|
752
|
+
children: [
|
|
753
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Stack__default.default, { direction: "row", alignItems: "center", justifyContent: "space-between", sx: { px: 1.5, py: 1, borderBottom: "1px solid", borderColor: "divider", flexShrink: 0 }, children: [
|
|
754
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Stack__default.default, { direction: "row", alignItems: "center", spacing: 1, children: [
|
|
755
|
+
/* @__PURE__ */ jsxRuntime.jsx(lu.LuBug, { size: 16 }),
|
|
756
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography__default.default, { variant: "subtitle2", sx: { fontWeight: 700 }, children: "Developer Logs" }),
|
|
757
|
+
/* @__PURE__ */ jsxRuntime.jsx(Chip__default.default, { label: `${filtered.length}/${logs.length}`, size: "small", variant: "soft", sx: { height: 18, fontSize: "0.65rem" } })
|
|
758
|
+
] }),
|
|
759
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Stack__default.default, { direction: "row", spacing: 0.5, children: [
|
|
760
|
+
/* @__PURE__ */ jsxRuntime.jsx(IconButton__default.default, { size: "small", onClick: clearDevLogs, disabled: logs.length === 0, children: /* @__PURE__ */ jsxRuntime.jsx(lu.LuTrash2, { size: 15 }) }),
|
|
761
|
+
/* @__PURE__ */ jsxRuntime.jsx(IconButton__default.default, { size: "small", onClick: onClose, children: /* @__PURE__ */ jsxRuntime.jsx(lu.LuX, { size: 16 }) })
|
|
762
|
+
] })
|
|
763
|
+
] }),
|
|
764
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Stack__default.default, { spacing: 1, sx: { px: 1.5, py: 1, borderBottom: "1px solid", borderColor: "divider", flexShrink: 0 }, children: [
|
|
765
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Stack__default.default, { direction: "row", spacing: 1, alignItems: "center", flexWrap: "wrap", useFlexGap: true, children: [
|
|
766
|
+
/* @__PURE__ */ jsxRuntime.jsx(ToggleButtonGroup__default.default, { size: "small", exclusive: true, value: source, onChange: (_, v) => v && setSource(v), children: ["all", "client", "server", "network"].map((v) => /* @__PURE__ */ jsxRuntime.jsx(ToggleButton__default.default, { value: v, sx: { px: 1, py: 0.25, fontSize: "0.7rem", textTransform: "capitalize" }, children: v }, v)) }),
|
|
767
|
+
/* @__PURE__ */ jsxRuntime.jsx(ToggleButton__default.default, { size: "small", value: "thisPage", selected: thisPageOnly, onChange: () => setThisPageOnly((v) => !v), sx: { px: 1, py: 0.25, fontSize: "0.7rem" }, children: "This page" })
|
|
768
|
+
] }),
|
|
769
|
+
/* @__PURE__ */ jsxRuntime.jsx(ToggleButtonGroup__default.default, { size: "small", exclusive: true, value: level, onChange: (_, v) => v && setLevel(v), children: ["all", "error", "warn", "info"].map((v) => /* @__PURE__ */ jsxRuntime.jsx(ToggleButton__default.default, { value: v, sx: { px: 1, py: 0.25, fontSize: "0.7rem", textTransform: "capitalize" }, children: v }, v)) }),
|
|
770
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
771
|
+
TextField__default.default,
|
|
772
|
+
{
|
|
773
|
+
size: "small",
|
|
774
|
+
placeholder: "Search...",
|
|
775
|
+
value: search,
|
|
776
|
+
onChange: (e) => setSearch2(e.target.value),
|
|
777
|
+
fullWidth: true,
|
|
778
|
+
slotProps: {
|
|
779
|
+
input: {
|
|
780
|
+
startAdornment: /* @__PURE__ */ jsxRuntime.jsx(InputAdornment__default.default, { position: "start", children: /* @__PURE__ */ jsxRuntime.jsx(lu.LuSearch, { size: 15 }) })
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
)
|
|
785
|
+
] }),
|
|
786
|
+
/* @__PURE__ */ jsxRuntime.jsx(Box6__default.default, { sx: { flex: 1, overflowY: "auto", p: 1 }, children: filtered.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(Typography__default.default, { variant: "body2", sx: { color: "text.disabled", textAlign: "center", py: 4 }, children: logs.length === 0 ? "No activity captured this session." : "No logs match the current filters." }) : /* @__PURE__ */ jsxRuntime.jsx(Stack__default.default, { spacing: 0.75, children: filtered.map((entry) => /* @__PURE__ */ jsxRuntime.jsx(LogRow, { entry, showPath: !thisPageOnly }, entry.id)) }) })
|
|
787
|
+
]
|
|
788
|
+
}
|
|
789
|
+
);
|
|
790
|
+
}
|
|
361
791
|
function useBadge() {
|
|
362
|
-
const logs = react.useSyncExternalStore(
|
|
363
|
-
const errors = logs.filter((l) => l.level === "error").length;
|
|
792
|
+
const logs = react.useSyncExternalStore(subscribeDevLogs, getDevLogs, getDevLogsServerSnapshot);
|
|
364
793
|
if (logs.length === 0) return null;
|
|
794
|
+
const errors = errorCount();
|
|
365
795
|
return errors > 0 ? { label: String(errors), tone: "error" } : { label: String(logs.length), tone: "neutral" };
|
|
366
796
|
}
|
|
367
797
|
var devLogsTool = {
|
|
368
798
|
id: "logs",
|
|
369
799
|
title: "Developer Logs",
|
|
370
|
-
subtitle: "Client & network activity",
|
|
800
|
+
subtitle: "Client, server & network activity",
|
|
371
801
|
color: "info",
|
|
372
|
-
icon: /* @__PURE__ */ jsxRuntime.jsx(
|
|
802
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(lu.LuBug, { size: 19 }),
|
|
373
803
|
Panel: DevLogsPanel,
|
|
374
804
|
useBadge,
|
|
375
|
-
init:
|
|
805
|
+
init: installDevLogCapture
|
|
376
806
|
};
|
|
377
807
|
function registerDevLogs() {
|
|
378
808
|
registerTool(devLogsTool);
|
|
@@ -392,12 +822,7 @@ function emit2() {
|
|
|
392
822
|
function record(m) {
|
|
393
823
|
metrics = {
|
|
394
824
|
...metrics,
|
|
395
|
-
[m.name]: {
|
|
396
|
-
name: m.name,
|
|
397
|
-
value: m.value,
|
|
398
|
-
rating: m.rating,
|
|
399
|
-
unit: m.name === "CLS" ? "" : "ms"
|
|
400
|
-
}
|
|
825
|
+
[m.name]: { name: m.name, value: m.value, rating: m.rating, unit: m.name === "CLS" ? "" : "ms" }
|
|
401
826
|
};
|
|
402
827
|
emit2();
|
|
403
828
|
}
|
|
@@ -423,134 +848,112 @@ function serverSnapshot() {
|
|
|
423
848
|
return EMPTY2;
|
|
424
849
|
}
|
|
425
850
|
var RATING_COLOR = {
|
|
426
|
-
good: "
|
|
427
|
-
"needs-improvement": "
|
|
428
|
-
poor: "
|
|
851
|
+
good: "success",
|
|
852
|
+
"needs-improvement": "warning",
|
|
853
|
+
poor: "error"
|
|
429
854
|
};
|
|
430
855
|
function PagePerformancePanel({ onClose }) {
|
|
431
856
|
const data = react.useSyncExternalStore(subscribe, snapshot, serverSnapshot);
|
|
432
857
|
const order = ["LCP", "INP", "CLS", "FCP", "TTFB"];
|
|
433
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
858
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
859
|
+
Box6__default.default,
|
|
860
|
+
{
|
|
861
|
+
"data-rdp-ignore": "",
|
|
862
|
+
sx: {
|
|
863
|
+
position: "fixed",
|
|
864
|
+
bottom: 96,
|
|
865
|
+
right: 24,
|
|
866
|
+
zIndex: (t) => t.zIndex.modal + 1,
|
|
867
|
+
width: "min(440px, calc(100vw - 32px))",
|
|
868
|
+
maxHeight: "min(70vh, 640px)",
|
|
869
|
+
display: "flex",
|
|
870
|
+
flexDirection: "column",
|
|
871
|
+
borderRadius: 2,
|
|
872
|
+
overflow: "hidden",
|
|
873
|
+
border: "1px solid",
|
|
874
|
+
borderColor: "divider",
|
|
875
|
+
bgcolor: "background.paper",
|
|
876
|
+
boxShadow: 12
|
|
877
|
+
},
|
|
878
|
+
children: [
|
|
879
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Stack__default.default, { direction: "row", alignItems: "center", justifyContent: "space-between", sx: { px: 1.5, py: 1, borderBottom: "1px solid", borderColor: "divider" }, children: [
|
|
880
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Stack__default.default, { direction: "row", alignItems: "center", spacing: 1, children: [
|
|
881
|
+
/* @__PURE__ */ jsxRuntime.jsx(lu.LuGauge, { size: 16 }),
|
|
882
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography__default.default, { variant: "subtitle2", sx: { fontWeight: 700 }, children: "Page Performance" })
|
|
452
883
|
] }),
|
|
453
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
454
|
-
] },
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
884
|
+
/* @__PURE__ */ jsxRuntime.jsx(IconButton__default.default, { size: "small", onClick: onClose, children: /* @__PURE__ */ jsxRuntime.jsx(lu.LuX, { size: 16 }) })
|
|
885
|
+
] }),
|
|
886
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Box6__default.default, { sx: { flex: 1, overflowY: "auto", p: 1.5 }, children: [
|
|
887
|
+
order.every((k) => !data[k]) && /* @__PURE__ */ jsxRuntime.jsx(Typography__default.default, { variant: "body2", sx: { color: "text.disabled" }, children: "Collecting Web Vitals\u2026 interact with the page (INP needs an interaction)." }),
|
|
888
|
+
order.map((key) => {
|
|
889
|
+
const m = data[key];
|
|
890
|
+
if (!m) return null;
|
|
891
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(Box6__default.default, { sx: { py: 1, borderBottom: "1px solid", borderColor: "divider" }, children: [
|
|
892
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Stack__default.default, { direction: "row", alignItems: "center", spacing: 1, children: [
|
|
893
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
894
|
+
Chip__default.default,
|
|
895
|
+
{
|
|
896
|
+
label: m.name,
|
|
897
|
+
size: "small",
|
|
898
|
+
color: RATING_COLOR[m.rating],
|
|
899
|
+
variant: "soft",
|
|
900
|
+
sx: { height: 20, fontSize: "0.65rem", fontWeight: 700 }
|
|
901
|
+
}
|
|
902
|
+
),
|
|
903
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Typography__default.default, { variant: "body2", sx: { fontFamily: "monospace", fontWeight: 700 }, children: [
|
|
904
|
+
m.unit === "ms" ? Math.round(m.value) : m.value.toFixed(3),
|
|
905
|
+
m.unit
|
|
906
|
+
] }),
|
|
907
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography__default.default, { variant: "caption", sx: { color: `${RATING_COLOR[m.rating]}.main`, ml: "auto" }, children: m.rating })
|
|
908
|
+
] }),
|
|
909
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography__default.default, { variant: "caption", sx: { color: "text.secondary", display: "block", mt: 0.25 }, children: HINTS[key] })
|
|
910
|
+
] }, key);
|
|
911
|
+
})
|
|
912
|
+
] })
|
|
913
|
+
]
|
|
914
|
+
}
|
|
915
|
+
);
|
|
458
916
|
}
|
|
459
917
|
var pagePerformanceTool = {
|
|
460
918
|
id: "perf",
|
|
461
919
|
title: "Page Performance",
|
|
462
920
|
subtitle: "Web Vitals & fix suggestions",
|
|
463
921
|
color: "warning",
|
|
464
|
-
icon: /* @__PURE__ */ jsxRuntime.jsx(
|
|
922
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(lu.LuGauge, { size: 19 }),
|
|
465
923
|
Panel: PagePerformancePanel,
|
|
466
924
|
init: installPerf
|
|
467
925
|
};
|
|
468
926
|
function registerPagePerformance() {
|
|
469
927
|
registerTool(pagePerformanceTool);
|
|
470
928
|
}
|
|
471
|
-
function buildProtocolUrl(editor, loc) {
|
|
472
|
-
const line = loc.line ?? 1;
|
|
473
|
-
const col = loc.column ?? 1;
|
|
474
|
-
switch (editor) {
|
|
475
|
-
case "cursor":
|
|
476
|
-
return `cursor://file/${loc.file}:${line}:${col}`;
|
|
477
|
-
case "webstorm":
|
|
478
|
-
return `webstorm://open?file=${encodeURIComponent(loc.file)}&line=${line}&column=${col}`;
|
|
479
|
-
case "zed":
|
|
480
|
-
return `zed://file/${loc.file}:${line}:${col}`;
|
|
481
|
-
case "vscode":
|
|
482
|
-
case "auto":
|
|
483
|
-
default:
|
|
484
|
-
return `vscode://file/${loc.file}:${line}:${col}`;
|
|
485
|
-
}
|
|
486
|
-
}
|
|
487
|
-
var defaultOpenInEditor = async (loc, editor = "auto") => {
|
|
488
|
-
const url = buildProtocolUrl(editor, loc);
|
|
489
|
-
if (url && typeof window !== "undefined") {
|
|
490
|
-
try {
|
|
491
|
-
window.location.assign(url);
|
|
492
|
-
return true;
|
|
493
|
-
} catch {
|
|
494
|
-
}
|
|
495
|
-
}
|
|
496
|
-
if (typeof navigator !== "undefined" && navigator.clipboard) {
|
|
497
|
-
await navigator.clipboard.writeText(`${loc.file}${loc.line ? `:${loc.line}` : ""}`).catch(() => void 0);
|
|
498
|
-
}
|
|
499
|
-
return false;
|
|
500
|
-
};
|
|
501
|
-
var DevPanelContext = react.createContext(null);
|
|
502
|
-
function resolve(config) {
|
|
503
|
-
const enabled = config.enabled ?? (typeof process !== "undefined" ? process.env.NODE_ENV !== "production" : true);
|
|
504
|
-
return {
|
|
505
|
-
enabled,
|
|
506
|
-
editor: config.editor ?? "auto",
|
|
507
|
-
getRoute: config.getRoute ?? (() => typeof location !== "undefined" ? location.pathname : void 0),
|
|
508
|
-
openInEditor: config.openInEditor ?? defaultOpenInEditor,
|
|
509
|
-
graphEndpoint: config.graphEndpoint,
|
|
510
|
-
theme: config.theme ?? {},
|
|
511
|
-
tools: config.tools
|
|
512
|
-
};
|
|
513
|
-
}
|
|
514
|
-
function DevPanelConfigProvider({
|
|
515
|
-
config,
|
|
516
|
-
children
|
|
517
|
-
}) {
|
|
518
|
-
const value = react.useMemo(() => resolve(config), [config]);
|
|
519
|
-
return /* @__PURE__ */ jsxRuntime.jsx(DevPanelContext.Provider, { value, children });
|
|
520
|
-
}
|
|
521
|
-
function useDevPanelConfig() {
|
|
522
|
-
const ctx = react.useContext(DevPanelContext);
|
|
523
|
-
if (!ctx) throw new Error("useDevPanelConfig must be used within <DevPanel> / DevPanelConfigProvider");
|
|
524
|
-
return ctx;
|
|
525
|
-
}
|
|
526
929
|
function GraphSearch({
|
|
527
930
|
value,
|
|
528
931
|
onChange,
|
|
529
932
|
placeholder = "Search components\u2026"
|
|
530
933
|
}) {
|
|
531
|
-
return /* @__PURE__ */ jsxRuntime.
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
934
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
935
|
+
TextField__default.default,
|
|
936
|
+
{
|
|
937
|
+
size: "small",
|
|
938
|
+
fullWidth: true,
|
|
939
|
+
placeholder,
|
|
940
|
+
value,
|
|
941
|
+
onChange: (e) => onChange(e.target.value),
|
|
942
|
+
slotProps: {
|
|
943
|
+
input: {
|
|
944
|
+
startAdornment: /* @__PURE__ */ jsxRuntime.jsx(InputAdornment__default.default, { position: "start", children: /* @__PURE__ */ jsxRuntime.jsx(lu.LuSearch, { size: 15 }) })
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
);
|
|
536
949
|
}
|
|
537
950
|
function Chips({ names, onSelect }) {
|
|
538
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
539
|
-
"button",
|
|
540
|
-
{
|
|
541
|
-
type: "button",
|
|
542
|
-
className: "rdp-chip rdp-mono",
|
|
543
|
-
style: { border: "1px solid var(--rdp-border)", background: "transparent", color: "var(--rdp-text)", cursor: "pointer" },
|
|
544
|
-
onClick: () => onSelect(n),
|
|
545
|
-
children: n
|
|
546
|
-
},
|
|
547
|
-
n
|
|
548
|
-
)) });
|
|
951
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Stack__default.default, { direction: "row", spacing: 0.5, useFlexGap: true, sx: { flexWrap: "wrap" }, children: names.map((n) => /* @__PURE__ */ jsxRuntime.jsx(Chip__default.default, { label: n, size: "small", variant: "outlined", onClick: () => onSelect(n), sx: { height: 18, fontSize: "0.62rem", fontFamily: "monospace" } }, n)) });
|
|
549
952
|
}
|
|
550
953
|
function Row({ label, children }) {
|
|
551
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
552
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
553
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
954
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(Stack__default.default, { direction: "row", spacing: 1, sx: { mt: 0.5 }, children: [
|
|
955
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography__default.default, { variant: "caption", sx: { minWidth: 56, color: "text.disabled", fontWeight: 600, flexShrink: 0 }, children: label }),
|
|
956
|
+
/* @__PURE__ */ jsxRuntime.jsx(Box6__default.default, { sx: { minWidth: 0, flex: 1 }, children })
|
|
554
957
|
] });
|
|
555
958
|
}
|
|
556
959
|
function NodeDetails({
|
|
@@ -561,57 +964,33 @@ function NodeDetails({
|
|
|
561
964
|
onSelectName
|
|
562
965
|
}) {
|
|
563
966
|
if (!selected) {
|
|
564
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
967
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Typography__default.default, { variant: "body2", sx: { color: "text.disabled", px: 0.5, py: 1 }, children: "Nothing selected. Enable inspect mode and click a component, or pick one from the tree." });
|
|
565
968
|
}
|
|
566
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
567
|
-
"
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
}
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
"=",
|
|
592
|
-
p.value
|
|
593
|
-
] }, p.name)) }) }),
|
|
594
|
-
/* @__PURE__ */ jsxRuntime.jsxs("button", { type: "button", className: cx("rdp-btn", "rdp-btn-primary"), style: { marginTop: 12 }, onClick: onOpen, children: [
|
|
595
|
-
/* @__PURE__ */ jsxRuntime.jsx(IconFileCode, { size: 14 }),
|
|
596
|
-
" Open in editor"
|
|
597
|
-
] }),
|
|
598
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", gap: 8, marginTop: 8 }, children: [
|
|
599
|
-
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "rdp-iconbtn", onClick: onCopyInfo, title: "Copy component info", children: /* @__PURE__ */ jsxRuntime.jsx(IconCopy, { size: 15 }) }),
|
|
600
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
601
|
-
"button",
|
|
602
|
-
{
|
|
603
|
-
type: "button",
|
|
604
|
-
className: "rdp-iconbtn",
|
|
605
|
-
onClick: onCopyPath,
|
|
606
|
-
disabled: !selected.filePath && !selected.absFilePath,
|
|
607
|
-
title: "Copy file path",
|
|
608
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(IconFileCode, { size: 15 })
|
|
609
|
-
}
|
|
610
|
-
)
|
|
611
|
-
] })
|
|
612
|
-
]
|
|
613
|
-
}
|
|
614
|
-
);
|
|
969
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(Box6__default.default, { sx: (t) => ({ p: 1.25, borderRadius: 1.5, border: "1px solid", borderColor: "divider", bgcolor: styles.alpha(t.palette.grey[500], 0.06) }), children: [
|
|
970
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Stack__default.default, { direction: "row", alignItems: "center", spacing: 0.75, children: [
|
|
971
|
+
/* @__PURE__ */ jsxRuntime.jsx(Chip__default.default, { label: selected.componentName, size: "small", color: "primary", variant: "soft", sx: { height: 20, fontSize: "0.68rem", fontWeight: 700 } }),
|
|
972
|
+
selected.domTag && /* @__PURE__ */ jsxRuntime.jsx(Typography__default.default, { variant: "caption", sx: { color: "text.disabled", fontFamily: "monospace" }, children: `<${selected.domTag}>` })
|
|
973
|
+
] }),
|
|
974
|
+
selected.filePath ? /* @__PURE__ */ jsxRuntime.jsxs(Typography__default.default, { variant: "caption", sx: { display: "block", mt: 0.75, fontFamily: "monospace", fontSize: "0.68rem", wordBreak: "break-all", color: "text.secondary" }, children: [
|
|
975
|
+
selected.filePath,
|
|
976
|
+
selected.line ? `:${selected.line}` : "",
|
|
977
|
+
selected.line && selected.column ? `:${selected.column}` : ""
|
|
978
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsx(Typography__default.default, { variant: "caption", sx: { display: "block", mt: 0.75, color: "warning.main" }, children: "No source path \u2014 run the graph generator (npx dev-panel-graph) or mount an adapter." }),
|
|
979
|
+
selected.route && /* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Route", children: /* @__PURE__ */ jsxRuntime.jsx(Typography__default.default, { variant: "caption", sx: { fontFamily: "monospace" }, children: selected.route }) }),
|
|
980
|
+
selected.parent && /* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Parent", children: /* @__PURE__ */ jsxRuntime.jsx(Chips, { names: [selected.parent], onSelect: onSelectName }) }),
|
|
981
|
+
selected.children.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Renders", children: /* @__PURE__ */ jsxRuntime.jsx(Chips, { names: selected.children, onSelect: onSelectName }) }),
|
|
982
|
+
selected.imports.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Imports", children: /* @__PURE__ */ jsxRuntime.jsx(Chips, { names: selected.imports, onSelect: onSelectName }) }),
|
|
983
|
+
selected.props && selected.props.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Props", children: /* @__PURE__ */ jsxRuntime.jsx(Box6__default.default, { sx: { fontFamily: "monospace", fontSize: "0.66rem", color: "text.secondary" }, children: selected.props.map((p) => /* @__PURE__ */ jsxRuntime.jsxs(Box6__default.default, { component: "span", sx: { mr: 1, display: "inline-block" }, children: [
|
|
984
|
+
/* @__PURE__ */ jsxRuntime.jsx(Box6__default.default, { component: "span", sx: { color: "primary.main" }, children: p.name }),
|
|
985
|
+
"=",
|
|
986
|
+
p.value
|
|
987
|
+
] }, p.name)) }) }),
|
|
988
|
+
/* @__PURE__ */ jsxRuntime.jsx(Button__default.default, { fullWidth: true, variant: "contained", startIcon: /* @__PURE__ */ jsxRuntime.jsx(lu.LuFileCode, { size: 14 }), onClick: onOpen, sx: { textTransform: "none", fontSize: "0.72rem", py: 0.4, mt: 1.25 }, children: "Open in editor" }),
|
|
989
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Stack__default.default, { direction: "row", spacing: 1, sx: { mt: 1 }, children: [
|
|
990
|
+
/* @__PURE__ */ jsxRuntime.jsx(Tooltip2__default.default, { title: "Copy component info", placement: "top", children: /* @__PURE__ */ jsxRuntime.jsx(IconButton__default.default, { size: "small", onClick: onCopyInfo, sx: { border: "1px solid", borderColor: "divider", borderRadius: 1 }, children: /* @__PURE__ */ jsxRuntime.jsx(lu.LuClipboardCopy, { size: 15 }) }) }),
|
|
991
|
+
/* @__PURE__ */ jsxRuntime.jsx(Tooltip2__default.default, { title: "Copy file path", placement: "top", children: /* @__PURE__ */ jsxRuntime.jsx("span", { children: /* @__PURE__ */ jsxRuntime.jsx(IconButton__default.default, { size: "small", onClick: onCopyPath, disabled: !selected.filePath && !selected.absFilePath, sx: { border: "1px solid", borderColor: "divider", borderRadius: 1 }, children: /* @__PURE__ */ jsxRuntime.jsx(lu.LuCopy, { size: 15 }) }) }) })
|
|
992
|
+
] })
|
|
993
|
+
] });
|
|
615
994
|
}
|
|
616
995
|
|
|
617
996
|
// src/tools/component-graph/graph-utils.ts
|
|
@@ -878,27 +1257,23 @@ function formatForCopy(s) {
|
|
|
878
1257
|
}
|
|
879
1258
|
var MAX_DEPTH = 6;
|
|
880
1259
|
function Label({ children }) {
|
|
881
|
-
return /* @__PURE__ */ jsxRuntime.jsx("
|
|
1260
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Typography__default.default, { variant: "caption", sx: { display: "block", mt: 1, mb: 0.25, color: "text.disabled", fontWeight: 700, textTransform: "uppercase", letterSpacing: 0.4, fontSize: "0.6rem" }, children });
|
|
882
1261
|
}
|
|
883
|
-
function RowActions({
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
onCopy
|
|
887
|
-
}) {
|
|
888
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("span", { style: { display: "inline-flex", gap: 2 }, children: [
|
|
889
|
-
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "rdp-iconbtn-bare", title: "Open in editor", onClick: (e) => {
|
|
1262
|
+
function RowActions({ node, onOpen, onCopy }) {
|
|
1263
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1264
|
+
/* @__PURE__ */ jsxRuntime.jsx(Tooltip2__default.default, { title: "Open in editor", placement: "top", children: /* @__PURE__ */ jsxRuntime.jsx(IconButton__default.default, { size: "small", sx: { p: 0.25 }, onClick: (e) => {
|
|
890
1265
|
e.stopPropagation();
|
|
891
1266
|
onOpen(node);
|
|
892
|
-
}, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
893
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1267
|
+
}, children: /* @__PURE__ */ jsxRuntime.jsx(lu.LuFileCode, { size: 13 }) }) }),
|
|
1268
|
+
/* @__PURE__ */ jsxRuntime.jsx(Tooltip2__default.default, { title: "Copy file path", placement: "top", children: /* @__PURE__ */ jsxRuntime.jsx(IconButton__default.default, { size: "small", sx: { p: 0.25 }, onClick: (e) => {
|
|
894
1269
|
e.stopPropagation();
|
|
895
1270
|
onCopy(node);
|
|
896
|
-
}, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1271
|
+
}, children: /* @__PURE__ */ jsxRuntime.jsx(lu.LuCopy, { size: 13 }) }) })
|
|
897
1272
|
] });
|
|
898
1273
|
}
|
|
899
1274
|
function RowShell({
|
|
900
1275
|
depth = 0,
|
|
901
|
-
active,
|
|
1276
|
+
active = false,
|
|
902
1277
|
caret,
|
|
903
1278
|
label,
|
|
904
1279
|
isRoute,
|
|
@@ -906,42 +1281,43 @@ function RowShell({
|
|
|
906
1281
|
actions
|
|
907
1282
|
}) {
|
|
908
1283
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
909
|
-
|
|
1284
|
+
Stack__default.default,
|
|
910
1285
|
{
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
1286
|
+
direction: "row",
|
|
1287
|
+
alignItems: "center",
|
|
1288
|
+
spacing: 0.5,
|
|
1289
|
+
sx: (t) => ({
|
|
1290
|
+
pl: 0.5 + depth * 1.5,
|
|
1291
|
+
pr: 0.5,
|
|
1292
|
+
py: 0.25,
|
|
1293
|
+
borderRadius: 1,
|
|
1294
|
+
bgcolor: active ? styles.alpha(t.palette.primary.main, 0.16) : "transparent",
|
|
1295
|
+
"&:hover": { bgcolor: active ? styles.alpha(t.palette.primary.main, 0.2) : "action.hover" },
|
|
1296
|
+
"&:hover .rdp-row-actions": { opacity: 1 }
|
|
1297
|
+
}),
|
|
919
1298
|
children: [
|
|
920
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1299
|
+
/* @__PURE__ */ jsxRuntime.jsx(Box6__default.default, { sx: { width: 16, display: "grid", placeItems: "center", color: "text.disabled" }, children: caret }),
|
|
921
1300
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
922
|
-
|
|
1301
|
+
Typography__default.default,
|
|
923
1302
|
{
|
|
924
|
-
type: "button",
|
|
925
1303
|
onClick: onLabel,
|
|
926
|
-
|
|
927
|
-
|
|
1304
|
+
variant: "caption",
|
|
1305
|
+
sx: {
|
|
928
1306
|
flex: 1,
|
|
929
1307
|
minWidth: 0,
|
|
930
|
-
textAlign: "left",
|
|
931
|
-
background: "none",
|
|
932
|
-
border: "none",
|
|
933
1308
|
cursor: "pointer",
|
|
934
|
-
fontSize: 12,
|
|
935
1309
|
fontWeight: active ? 700 : 500,
|
|
936
|
-
|
|
937
|
-
|
|
1310
|
+
fontFamily: "monospace",
|
|
1311
|
+
fontSize: "0.72rem",
|
|
938
1312
|
overflow: "hidden",
|
|
939
|
-
textOverflow: "ellipsis"
|
|
1313
|
+
textOverflow: "ellipsis",
|
|
1314
|
+
whiteSpace: "nowrap",
|
|
1315
|
+
color: isRoute ? "info.main" : active ? "primary.main" : "text.primary"
|
|
940
1316
|
},
|
|
941
1317
|
children: label
|
|
942
1318
|
}
|
|
943
1319
|
),
|
|
944
|
-
actions
|
|
1320
|
+
actions && /* @__PURE__ */ jsxRuntime.jsx(Stack__default.default, { direction: "row", spacing: 0.25, className: "rdp-row-actions", sx: { opacity: 0, transition: "opacity 120ms" }, children: actions })
|
|
945
1321
|
]
|
|
946
1322
|
}
|
|
947
1323
|
);
|
|
@@ -953,14 +1329,14 @@ function Branch({ name, depth, trail, p }) {
|
|
|
953
1329
|
const hasKids = kids.length > 0 && depth < MAX_DEPTH && !trail.has(id);
|
|
954
1330
|
const open = p.expanded.has(id);
|
|
955
1331
|
const active = p.selected?.nodeId === id || p.selected?.componentName === name;
|
|
956
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1332
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(Box6__default.default, { children: [
|
|
957
1333
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
958
1334
|
RowShell,
|
|
959
1335
|
{
|
|
960
1336
|
depth,
|
|
961
1337
|
active,
|
|
962
1338
|
isRoute: node?.type === "route",
|
|
963
|
-
caret: hasKids ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1339
|
+
caret: hasKids ? /* @__PURE__ */ jsxRuntime.jsx(Box6__default.default, { sx: { cursor: "pointer", display: "grid", placeItems: "center" }, onClick: () => p.onToggle(id), children: open ? /* @__PURE__ */ jsxRuntime.jsx(lu.LuChevronDown, { size: 13 }) : /* @__PURE__ */ jsxRuntime.jsx(lu.LuChevronRight, { size: 13 }) }) : null,
|
|
964
1340
|
label: name,
|
|
965
1341
|
onLabel: () => node && p.onSelect(node),
|
|
966
1342
|
actions: node ? /* @__PURE__ */ jsxRuntime.jsx(RowActions, { node, onOpen: p.onOpen, onCopy: p.onCopy }) : null
|
|
@@ -973,7 +1349,7 @@ function ComponentGraphTree(p) {
|
|
|
973
1349
|
const { graph, selected, search } = p;
|
|
974
1350
|
if (graph && search.trim()) {
|
|
975
1351
|
const results = searchNodes(graph, search);
|
|
976
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1352
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(Box6__default.default, { children: [
|
|
977
1353
|
/* @__PURE__ */ jsxRuntime.jsxs(Label, { children: [
|
|
978
1354
|
results.length,
|
|
979
1355
|
" match",
|
|
@@ -990,7 +1366,7 @@ function ComponentGraphTree(p) {
|
|
|
990
1366
|
},
|
|
991
1367
|
node.id
|
|
992
1368
|
)),
|
|
993
|
-
results.length === 0 && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1369
|
+
results.length === 0 && /* @__PURE__ */ jsxRuntime.jsxs(Typography__default.default, { variant: "caption", sx: { color: "text.disabled", pl: 1 }, children: [
|
|
994
1370
|
"No components match \u201C",
|
|
995
1371
|
search,
|
|
996
1372
|
"\u201D."
|
|
@@ -998,9 +1374,9 @@ function ComponentGraphTree(p) {
|
|
|
998
1374
|
] });
|
|
999
1375
|
}
|
|
1000
1376
|
if (!selected) {
|
|
1001
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1377
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Typography__default.default, { variant: "body2", sx: { color: "text.disabled", px: 0.5, py: 1 }, children: "Lock a component (hover + click) or search above to explore the tree." });
|
|
1002
1378
|
}
|
|
1003
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1379
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(Box6__default.default, { children: [
|
|
1004
1380
|
selected.parents.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1005
1381
|
/* @__PURE__ */ jsxRuntime.jsx(Label, { children: "Parent chain" }),
|
|
1006
1382
|
selected.parents.map((parent) => {
|
|
@@ -1009,7 +1385,7 @@ function ComponentGraphTree(p) {
|
|
|
1009
1385
|
RowShell,
|
|
1010
1386
|
{
|
|
1011
1387
|
isRoute: node?.type === "route",
|
|
1012
|
-
caret: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1388
|
+
caret: /* @__PURE__ */ jsxRuntime.jsx(lu.LuArrowUp, { size: 12 }),
|
|
1013
1389
|
label: parent,
|
|
1014
1390
|
onLabel: () => node && p.onSelect(node),
|
|
1015
1391
|
actions: node ? /* @__PURE__ */ jsxRuntime.jsx(RowActions, { node, onOpen: p.onOpen, onCopy: p.onCopy }) : null
|
|
@@ -1019,13 +1395,13 @@ function ComponentGraphTree(p) {
|
|
|
1019
1395
|
})
|
|
1020
1396
|
] }),
|
|
1021
1397
|
/* @__PURE__ */ jsxRuntime.jsx(Label, { children: "Selected" }),
|
|
1022
|
-
/* @__PURE__ */ jsxRuntime.jsx(RowShell, { active: true, label: selected.componentName, onLabel: () => void 0 }),
|
|
1398
|
+
/* @__PURE__ */ jsxRuntime.jsx(RowShell, { active: true, label: selected.componentName, onLabel: () => void 0, actions: /* @__PURE__ */ jsxRuntime.jsx(Chip__default.default, { size: "small", variant: "soft", color: "primary", label: selected.source, sx: { height: 16, fontSize: "0.55rem", fontWeight: 700 } }) }),
|
|
1023
1399
|
/* @__PURE__ */ jsxRuntime.jsxs(Label, { children: [
|
|
1024
1400
|
"Renders (",
|
|
1025
1401
|
selected.children.length,
|
|
1026
1402
|
")"
|
|
1027
1403
|
] }),
|
|
1028
|
-
selected.children.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1404
|
+
selected.children.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(Typography__default.default, { variant: "caption", sx: { color: "text.disabled", pl: 1.5 }, children: "No child components detected." }) : selected.children.map((c) => /* @__PURE__ */ jsxRuntime.jsx(Branch, { name: c, depth: 0, trail: new Set(selected.nodeId ? [selected.nodeId] : []), p }, `c:${c}`)),
|
|
1029
1405
|
selected.imports.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1030
1406
|
/* @__PURE__ */ jsxRuntime.jsxs(Label, { children: [
|
|
1031
1407
|
"Imports (",
|
|
@@ -1072,56 +1448,60 @@ function ComponentGraphPageList({
|
|
|
1072
1448
|
};
|
|
1073
1449
|
}, [scan, route]);
|
|
1074
1450
|
if (!graph) {
|
|
1075
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1451
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Typography__default.default, { variant: "body2", sx: { color: "text.disabled", px: 0.5, py: 1 }, children: "Load the component graph (Graph tab) to map mounted components to source files." });
|
|
1076
1452
|
}
|
|
1077
1453
|
const q = query.trim().toLowerCase();
|
|
1078
1454
|
const filtered = q ? items.filter((i) => i.name.toLowerCase().includes(q) || i.node.filePath.toLowerCase().includes(q)) : items;
|
|
1079
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1080
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1081
|
-
/* @__PURE__ */ jsxRuntime.jsxs("
|
|
1082
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1083
|
-
" \xB7",
|
|
1455
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(Box6__default.default, { children: [
|
|
1456
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Stack__default.default, { direction: "row", alignItems: "center", justifyContent: "space-between", sx: { mb: 0.5 }, children: [
|
|
1457
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Typography__default.default, { variant: "caption", sx: { color: "text.secondary" }, children: [
|
|
1458
|
+
/* @__PURE__ */ jsxRuntime.jsx(Box6__default.default, { component: "span", sx: { fontFamily: "monospace", color: "info.main" }, children: route ?? "/" }),
|
|
1084
1459
|
" ",
|
|
1460
|
+
"\xB7 ",
|
|
1085
1461
|
q ? `${filtered.length} / ${items.length}` : items.length,
|
|
1086
1462
|
" component",
|
|
1087
1463
|
items.length === 1 ? "" : "s"
|
|
1088
1464
|
] }),
|
|
1089
|
-
/* @__PURE__ */ jsxRuntime.
|
|
1090
|
-
/* @__PURE__ */ jsxRuntime.jsx(IconRefresh, { size: 13 }),
|
|
1091
|
-
" Rescan"
|
|
1092
|
-
] })
|
|
1465
|
+
/* @__PURE__ */ jsxRuntime.jsx(Button__default.default, { size: "small", startIcon: /* @__PURE__ */ jsxRuntime.jsx(lu.LuRefreshCw, { size: 13 }), onClick: scan, sx: { textTransform: "none", fontSize: "0.7rem", py: 0.25 }, children: "Rescan" })
|
|
1093
1466
|
] }),
|
|
1094
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1095
|
-
items.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1467
|
+
/* @__PURE__ */ jsxRuntime.jsx(Box6__default.default, { sx: { mb: 1 }, children: /* @__PURE__ */ jsxRuntime.jsx(GraphSearch, { value: query, onChange: setQuery, placeholder: "Filter components on this page\u2026" }) }),
|
|
1468
|
+
items.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(Typography__default.default, { variant: "caption", sx: { color: "text.disabled", pl: 0.5 }, children: "No graph components detected in the live tree. Try Rescan, or regenerate the graph." }) : filtered.length === 0 ? /* @__PURE__ */ jsxRuntime.jsxs(Typography__default.default, { variant: "caption", sx: { color: "text.disabled", pl: 0.5 }, children: [
|
|
1096
1469
|
"No components match \u201C",
|
|
1097
1470
|
query,
|
|
1098
1471
|
"\u201D."
|
|
1099
1472
|
] }) : filtered.map(({ name, node, count }) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1100
|
-
|
|
1473
|
+
Stack__default.default,
|
|
1101
1474
|
{
|
|
1102
|
-
|
|
1103
|
-
|
|
1475
|
+
direction: "row",
|
|
1476
|
+
alignItems: "center",
|
|
1477
|
+
spacing: 0.5,
|
|
1104
1478
|
onClick: () => onSelect(node),
|
|
1479
|
+
sx: (t) => ({
|
|
1480
|
+
px: 0.5,
|
|
1481
|
+
py: 0.4,
|
|
1482
|
+
borderRadius: 1,
|
|
1483
|
+
cursor: "pointer",
|
|
1484
|
+
bgcolor: selectedName === name ? styles.alpha(t.palette.primary.main, 0.16) : "transparent",
|
|
1485
|
+
"&:hover": { bgcolor: "action.hover" },
|
|
1486
|
+
"&:hover .rdp-row-actions": { opacity: 1 }
|
|
1487
|
+
}),
|
|
1105
1488
|
children: [
|
|
1106
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1107
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1108
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1109
|
-
count > 1 && /* @__PURE__ */ jsxRuntime.
|
|
1110
|
-
"\xD7",
|
|
1111
|
-
count
|
|
1112
|
-
] })
|
|
1489
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Box6__default.default, { sx: { flex: 1, minWidth: 0 }, children: [
|
|
1490
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Stack__default.default, { direction: "row", alignItems: "center", spacing: 0.5, children: [
|
|
1491
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography__default.default, { variant: "caption", sx: { fontFamily: "monospace", fontWeight: 600, fontSize: "0.72rem", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }, children: name }),
|
|
1492
|
+
count > 1 && /* @__PURE__ */ jsxRuntime.jsx(Chip__default.default, { label: `\xD7${count}`, size: "small", variant: "soft", sx: { height: 15, fontSize: "0.55rem", "& .MuiChip-label": { px: 0.5 } } })
|
|
1113
1493
|
] }),
|
|
1114
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1494
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography__default.default, { variant: "caption", sx: { display: "block", color: "text.disabled", fontSize: "0.62rem", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }, children: node.filePath })
|
|
1115
1495
|
] }),
|
|
1116
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1117
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1496
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Stack__default.default, { direction: "row", spacing: 0.25, className: "rdp-row-actions", sx: { opacity: 0, transition: "opacity 120ms" }, children: [
|
|
1497
|
+
/* @__PURE__ */ jsxRuntime.jsx(Tooltip2__default.default, { title: "Open in editor", placement: "top", children: /* @__PURE__ */ jsxRuntime.jsx(IconButton__default.default, { size: "small", sx: { p: 0.25 }, onClick: (e) => {
|
|
1118
1498
|
e.stopPropagation();
|
|
1119
1499
|
onOpen(node);
|
|
1120
|
-
}, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1121
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1500
|
+
}, children: /* @__PURE__ */ jsxRuntime.jsx(lu.LuFileCode, { size: 13 }) }) }),
|
|
1501
|
+
/* @__PURE__ */ jsxRuntime.jsx(Tooltip2__default.default, { title: "Copy file path", placement: "top", children: /* @__PURE__ */ jsxRuntime.jsx(IconButton__default.default, { size: "small", sx: { p: 0.25 }, onClick: (e) => {
|
|
1122
1502
|
e.stopPropagation();
|
|
1123
1503
|
onCopy(node);
|
|
1124
|
-
}, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1504
|
+
}, children: /* @__PURE__ */ jsxRuntime.jsx(lu.LuCopy, { size: 13 }) }) })
|
|
1125
1505
|
] })
|
|
1126
1506
|
]
|
|
1127
1507
|
},
|
|
@@ -1223,10 +1603,10 @@ function loadGraph(endpoint, force = false) {
|
|
|
1223
1603
|
return graphPromise;
|
|
1224
1604
|
}
|
|
1225
1605
|
var TABS = [
|
|
1226
|
-
{ value: "hover", label: "Hover", icon: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1227
|
-
{ value: "graph", label: "Graph", icon: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1228
|
-
{ value: "page", label: "Page", icon: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1229
|
-
{ value: "file", label: "File", icon: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1606
|
+
{ value: "hover", label: "Hover", icon: /* @__PURE__ */ jsxRuntime.jsx(lu.LuMousePointerClick, { size: 14 }) },
|
|
1607
|
+
{ value: "graph", label: "Graph", icon: /* @__PURE__ */ jsxRuntime.jsx(lu.LuWorkflow, { size: 14 }) },
|
|
1608
|
+
{ value: "page", label: "Page", icon: /* @__PURE__ */ jsxRuntime.jsx(lu.LuLayers, { size: 14 }) },
|
|
1609
|
+
{ value: "file", label: "File", icon: /* @__PURE__ */ jsxRuntime.jsx(lu.LuFile, { size: 14 }) }
|
|
1230
1610
|
];
|
|
1231
1611
|
async function copy(text) {
|
|
1232
1612
|
if (typeof navigator === "undefined" || !navigator.clipboard) return false;
|
|
@@ -1237,16 +1617,14 @@ async function copy(text) {
|
|
|
1237
1617
|
}
|
|
1238
1618
|
function ComponentGraphPanel({ onClose }) {
|
|
1239
1619
|
const state2 = react.useSyncExternalStore(subscribeGraph, getGraphState, getGraphServerState);
|
|
1620
|
+
const theme = styles.useTheme();
|
|
1240
1621
|
const config = useDevPanelConfig();
|
|
1241
1622
|
const route = config.getRoute();
|
|
1242
1623
|
const { enabled, mode, selected, graph, status, search, expanded } = state2;
|
|
1243
1624
|
const openLoc = react.useCallback(
|
|
1244
1625
|
async (sel) => {
|
|
1245
1626
|
const file = sel?.absFilePath ?? sel?.filePath;
|
|
1246
|
-
if (!file) {
|
|
1247
|
-
showToast({ message: "No source path available", tone: "error" });
|
|
1248
|
-
return;
|
|
1249
|
-
}
|
|
1627
|
+
if (!file) return showToast({ message: "No source path available", tone: "error" });
|
|
1250
1628
|
const ok = await config.openInEditor?.({ file, line: sel?.line, column: sel?.column }, config.editor);
|
|
1251
1629
|
showToast(ok === false ? { message: "Editor unavailable \u2014 path copied", tone: "info" } : { message: "Opening in your editor\u2026", tone: "success" });
|
|
1252
1630
|
},
|
|
@@ -1256,14 +1634,11 @@ function ComponentGraphPanel({ onClose }) {
|
|
|
1256
1634
|
if (!selected) return;
|
|
1257
1635
|
void copy(formatForCopy(selected)).then((ok) => showToast({ message: ok ? "Component info copied" : "Copy failed", tone: ok ? "success" : "error" }));
|
|
1258
1636
|
}, [selected]);
|
|
1259
|
-
const copyPath = react.useCallback(
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
},
|
|
1265
|
-
[]
|
|
1266
|
-
);
|
|
1637
|
+
const copyPath = react.useCallback((sel) => {
|
|
1638
|
+
const path = sel?.filePath ?? sel?.absFilePath;
|
|
1639
|
+
if (!path) return showToast({ message: "No path to copy", tone: "info" });
|
|
1640
|
+
void copy(`${path}${sel?.line ? `:${sel.line}` : ""}`).then((ok) => showToast({ message: ok ? "File path copied" : "Copy failed", tone: ok ? "success" : "error" }));
|
|
1641
|
+
}, []);
|
|
1267
1642
|
const selectName = react.useCallback(
|
|
1268
1643
|
(name) => {
|
|
1269
1644
|
const node = graph?.nodes.find((n) => n.name === name || n.id === name);
|
|
@@ -1280,130 +1655,113 @@ function ComponentGraphPanel({ onClose }) {
|
|
|
1280
1655
|
if (status === "empty") return "Graph not generated \u2014 run `npx dev-panel-graph` (or add an adapter)";
|
|
1281
1656
|
return "Graph endpoint unavailable.";
|
|
1282
1657
|
}, [status, graph]);
|
|
1283
|
-
const details = /* @__PURE__ */ jsxRuntime.jsx(
|
|
1284
|
-
|
|
1658
|
+
const details = /* @__PURE__ */ jsxRuntime.jsx(NodeDetails, { selected, onOpen: () => void openLoc(selected), onCopyInfo: copyInfo, onCopyPath: () => copyPath(selected), onSelectName: selectName });
|
|
1659
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1660
|
+
Box6__default.default,
|
|
1285
1661
|
{
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
justifyContent: "space-between"
|
|
1312
|
-
},
|
|
1313
|
-
children: [
|
|
1314
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
1315
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "rdp-title", style: { display: "block" }, children: "Inspect mode" }),
|
|
1316
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "rdp-sub", children: enabled ? "Hover the UI, click to lock \xB7 Esc to exit" : "Enable, then hover the UI" })
|
|
1317
|
-
] }),
|
|
1318
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1319
|
-
"button",
|
|
1320
|
-
{
|
|
1321
|
-
type: "button",
|
|
1322
|
-
className: cx("rdp-btn", enabled && "rdp-btn-primary"),
|
|
1323
|
-
style: { width: "auto" },
|
|
1324
|
-
onClick: () => toggleInspector(config.graphEndpoint),
|
|
1325
|
-
children: enabled ? "On" : "Enable"
|
|
1326
|
-
}
|
|
1327
|
-
)
|
|
1328
|
-
]
|
|
1329
|
-
}
|
|
1330
|
-
),
|
|
1331
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "rdp-tabs", style: { marginTop: 12 }, children: TABS.map((t) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1332
|
-
"button",
|
|
1333
|
-
{
|
|
1334
|
-
type: "button",
|
|
1335
|
-
className: "rdp-tab",
|
|
1336
|
-
"aria-selected": mode === t.value,
|
|
1337
|
-
onClick: () => {
|
|
1338
|
-
setMode(t.value);
|
|
1339
|
-
if (t.value === "graph" || t.value === "page") void loadGraph(config.graphEndpoint);
|
|
1340
|
-
},
|
|
1341
|
-
children: [
|
|
1342
|
-
t.icon,
|
|
1343
|
-
t.label
|
|
1344
|
-
]
|
|
1345
|
-
},
|
|
1346
|
-
t.value
|
|
1347
|
-
)) }),
|
|
1348
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: { marginTop: 12 }, children: [
|
|
1349
|
-
mode === "hover" && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
1350
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "rdp-section-label", children: "Last locked component" }),
|
|
1351
|
-
details
|
|
1662
|
+
"data-rdp-ignore": "",
|
|
1663
|
+
sx: {
|
|
1664
|
+
position: "fixed",
|
|
1665
|
+
bottom: 96,
|
|
1666
|
+
right: 24,
|
|
1667
|
+
zIndex: (t) => t.zIndex.modal + 1,
|
|
1668
|
+
width: "min(460px, calc(100vw - 32px))",
|
|
1669
|
+
maxHeight: "min(78vh, 720px)",
|
|
1670
|
+
display: "flex",
|
|
1671
|
+
flexDirection: "column",
|
|
1672
|
+
borderRadius: 2,
|
|
1673
|
+
overflow: "hidden",
|
|
1674
|
+
border: "1px solid",
|
|
1675
|
+
borderColor: "divider",
|
|
1676
|
+
bgcolor: "background.paper",
|
|
1677
|
+
boxShadow: 12
|
|
1678
|
+
},
|
|
1679
|
+
children: [
|
|
1680
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Stack__default.default, { direction: "row", alignItems: "center", justifyContent: "space-between", sx: { px: 1.5, py: 1, borderBottom: "1px solid", borderColor: "divider", flexShrink: 0 }, children: [
|
|
1681
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Stack__default.default, { direction: "row", alignItems: "center", spacing: 1, children: [
|
|
1682
|
+
/* @__PURE__ */ jsxRuntime.jsx(lu.LuWorkflow, { size: 16 }),
|
|
1683
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography__default.default, { variant: "subtitle2", sx: { fontWeight: 700 }, children: "Component Graph Inspector" }),
|
|
1684
|
+
enabled && /* @__PURE__ */ jsxRuntime.jsx(Chip__default.default, { label: "ON", size: "small", color: "success", variant: "soft", sx: { height: 18, fontSize: "0.6rem", fontWeight: 700 } })
|
|
1685
|
+
] }),
|
|
1686
|
+
/* @__PURE__ */ jsxRuntime.jsx(IconButton__default.default, { size: "small", onClick: onClose, "aria-label": "Close", children: /* @__PURE__ */ jsxRuntime.jsx(lu.LuX, { size: 16 }) })
|
|
1352
1687
|
] }),
|
|
1353
|
-
|
|
1354
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1355
|
-
|
|
1356
|
-
/* @__PURE__ */ jsxRuntime.jsx(GraphSearch, { value: search, onChange: setSearch }),
|
|
1357
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { marginTop: 8 }, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1358
|
-
ComponentGraphTree,
|
|
1688
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Box6__default.default, { sx: { flex: 1, overflowY: "auto", p: 1.5 }, children: [
|
|
1689
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1690
|
+
Box6__default.default,
|
|
1359
1691
|
{
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1692
|
+
sx: {
|
|
1693
|
+
p: 1.25,
|
|
1694
|
+
borderRadius: 1.5,
|
|
1695
|
+
border: "1px solid",
|
|
1696
|
+
borderColor: enabled ? styles.alpha(theme.palette.success.main, 0.5) : "divider",
|
|
1697
|
+
bgcolor: enabled ? styles.alpha(theme.palette.success.main, 0.08) : "background.default"
|
|
1698
|
+
},
|
|
1699
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(Stack__default.default, { direction: "row", alignItems: "center", justifyContent: "space-between", children: [
|
|
1700
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Box6__default.default, { children: [
|
|
1701
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography__default.default, { variant: "body2", sx: { fontWeight: 700 }, children: "Inspect mode" }),
|
|
1702
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography__default.default, { variant: "caption", sx: { color: "text.secondary" }, children: enabled ? "Hover the UI, click to lock \xB7 Esc to exit" : "Enable, then hover the UI" })
|
|
1703
|
+
] }),
|
|
1704
|
+
/* @__PURE__ */ jsxRuntime.jsx(Switch__default.default, { checked: enabled, onChange: () => toggleInspector(config.graphEndpoint) })
|
|
1705
|
+
] })
|
|
1368
1706
|
}
|
|
1369
|
-
)
|
|
1370
|
-
selected && !search.trim() && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { marginTop: 12 }, children: details })
|
|
1371
|
-
] }),
|
|
1372
|
-
mode === "page" && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
1707
|
+
),
|
|
1373
1708
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1374
|
-
|
|
1709
|
+
ToggleButtonGroup__default.default,
|
|
1375
1710
|
{
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1711
|
+
fullWidth: true,
|
|
1712
|
+
exclusive: true,
|
|
1713
|
+
size: "small",
|
|
1714
|
+
value: mode,
|
|
1715
|
+
onChange: (_, next) => {
|
|
1716
|
+
if (!next) return;
|
|
1717
|
+
setMode(next);
|
|
1718
|
+
if (next === "graph" || next === "page") void loadGraph(config.graphEndpoint);
|
|
1719
|
+
},
|
|
1720
|
+
sx: { mt: 1.5 },
|
|
1721
|
+
children: TABS.map((t) => /* @__PURE__ */ jsxRuntime.jsxs(ToggleButton__default.default, { value: t.value, sx: { textTransform: "none", gap: 0.5, py: 0.5 }, children: [
|
|
1722
|
+
t.icon,
|
|
1723
|
+
t.label
|
|
1724
|
+
] }, t.value))
|
|
1382
1725
|
}
|
|
1383
1726
|
),
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1727
|
+
/* @__PURE__ */ jsxRuntime.jsx(Divider__default.default, { sx: { my: 1.5 } }),
|
|
1728
|
+
mode === "hover" && /* @__PURE__ */ jsxRuntime.jsxs(Box6__default.default, { children: [
|
|
1729
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography__default.default, { variant: "caption", sx: { color: "text.disabled", fontWeight: 700, textTransform: "uppercase", letterSpacing: 0.4 }, children: "Last locked component" }),
|
|
1730
|
+
/* @__PURE__ */ jsxRuntime.jsx(Box6__default.default, { sx: { mt: 0.5 }, children: details })
|
|
1731
|
+
] }),
|
|
1732
|
+
mode === "graph" && /* @__PURE__ */ jsxRuntime.jsxs(Box6__default.default, { children: [
|
|
1733
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography__default.default, { variant: "caption", sx: { display: "block", mb: 0.5, color: status === "ready" ? "success.main" : "text.disabled" }, children: statusText }),
|
|
1734
|
+
(status === "empty" || status === "error") && /* @__PURE__ */ jsxRuntime.jsx(Chip__default.default, { size: "small", variant: "outlined", label: "Retry graph load", onClick: () => loadGraph(config.graphEndpoint, true), sx: { mb: 1, height: 22, fontSize: "0.65rem" } }),
|
|
1735
|
+
/* @__PURE__ */ jsxRuntime.jsx(GraphSearch, { value: search, onChange: setSearch }),
|
|
1736
|
+
/* @__PURE__ */ jsxRuntime.jsx(Box6__default.default, { sx: { mt: 1 }, children: /* @__PURE__ */ jsxRuntime.jsx(ComponentGraphTree, { graph, selected, search, expanded, onSelect: selectNode, onToggle: toggleExpanded, onOpen: openNode, onCopy: copyNode }) }),
|
|
1737
|
+
selected && !search.trim() && /* @__PURE__ */ jsxRuntime.jsx(Box6__default.default, { sx: { mt: 1.5 }, children: details })
|
|
1738
|
+
] }),
|
|
1739
|
+
mode === "page" && /* @__PURE__ */ jsxRuntime.jsxs(Box6__default.default, { children: [
|
|
1740
|
+
/* @__PURE__ */ jsxRuntime.jsx(ComponentGraphPageList, { graph, route, selectedName: selected?.componentName, onSelect: selectNode, onOpen: openNode, onCopy: copyNode }),
|
|
1741
|
+
selected && /* @__PURE__ */ jsxRuntime.jsx(Box6__default.default, { sx: { mt: 1.5 }, children: details })
|
|
1742
|
+
] }),
|
|
1743
|
+
mode === "file" && details
|
|
1744
|
+
] })
|
|
1745
|
+
]
|
|
1746
|
+
}
|
|
1747
|
+
);
|
|
1390
1748
|
}
|
|
1749
|
+
var TOOLTIP_W = 360;
|
|
1391
1750
|
function ComponentGraphOverlay() {
|
|
1392
1751
|
const state2 = react.useSyncExternalStore(subscribeGraph, getGraphState, getGraphServerState);
|
|
1752
|
+
const theme = styles.useTheme();
|
|
1393
1753
|
const config = useDevPanelConfig();
|
|
1394
|
-
const [hover, setHover] = react.useState(null);
|
|
1395
1754
|
const route = config.getRoute();
|
|
1396
1755
|
const { enabled } = state2;
|
|
1397
|
-
const
|
|
1398
|
-
|
|
1756
|
+
const [hover, setHover] = react.useState(null);
|
|
1757
|
+
const open = react.useCallback(
|
|
1758
|
+
async (file, line, column) => {
|
|
1399
1759
|
if (!file) {
|
|
1400
|
-
showToast({ message: "No source path \u2014 generate the graph
|
|
1760
|
+
showToast({ message: "No source path \u2014 generate the graph", tone: "error" });
|
|
1401
1761
|
return;
|
|
1402
1762
|
}
|
|
1403
1763
|
const ok = await config.openInEditor?.({ file, line, column }, config.editor);
|
|
1404
|
-
showToast(
|
|
1405
|
-
ok === false ? { message: `Editor unavailable \u2014 path copied (${name ?? ""})`, tone: "info" } : { message: "Opening in your editor\u2026", tone: "success" }
|
|
1406
|
-
);
|
|
1764
|
+
showToast(ok === false ? { message: "Editor unavailable \u2014 path copied", tone: "info" } : { message: "Opening in your editor\u2026", tone: "success" });
|
|
1407
1765
|
},
|
|
1408
1766
|
[config]
|
|
1409
1767
|
);
|
|
@@ -1447,11 +1805,8 @@ function ComponentGraphOverlay() {
|
|
|
1447
1805
|
e.stopPropagation();
|
|
1448
1806
|
setSelected(sel);
|
|
1449
1807
|
setMode("graph");
|
|
1450
|
-
if (e.metaKey || e.ctrlKey)
|
|
1451
|
-
|
|
1452
|
-
} else {
|
|
1453
|
-
showToast({ message: `Locked ${sel.componentName}`, tone: "success" });
|
|
1454
|
-
}
|
|
1808
|
+
if (e.metaKey || e.ctrlKey) void open(sel.absFilePath ?? sel.filePath, sel.line, sel.column);
|
|
1809
|
+
else showToast({ message: `Locked ${sel.componentName}`, tone: "success" });
|
|
1455
1810
|
};
|
|
1456
1811
|
document.addEventListener("pointermove", onMove, { passive: true });
|
|
1457
1812
|
document.addEventListener("keydown", onKey, true);
|
|
@@ -1463,47 +1818,92 @@ function ComponentGraphOverlay() {
|
|
|
1463
1818
|
document.removeEventListener("click", onClick, true);
|
|
1464
1819
|
setHover(null);
|
|
1465
1820
|
};
|
|
1466
|
-
}, [enabled, route,
|
|
1821
|
+
}, [enabled, route, open]);
|
|
1467
1822
|
if (!enabled) return null;
|
|
1468
|
-
const flipX = typeof window !== "undefined" && hover && hover.x +
|
|
1823
|
+
const flipX = typeof window !== "undefined" && hover && hover.x + TOOLTIP_W + 14 > window.innerWidth;
|
|
1469
1824
|
const flipY = typeof window !== "undefined" && hover && hover.y + 140 > window.innerHeight;
|
|
1470
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("
|
|
1825
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(Box6__default.default, { "data-rdp-ignore": "", sx: { position: "fixed", inset: 0, pointerEvents: "none", zIndex: (t) => t.zIndex.tooltip + 1 }, children: [
|
|
1471
1826
|
hover && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1472
|
-
|
|
1827
|
+
Box6__default.default,
|
|
1473
1828
|
{
|
|
1474
|
-
|
|
1475
|
-
|
|
1829
|
+
sx: {
|
|
1830
|
+
position: "fixed",
|
|
1831
|
+
top: hover.rect.top,
|
|
1832
|
+
left: hover.rect.left,
|
|
1833
|
+
width: hover.rect.width,
|
|
1834
|
+
height: hover.rect.height,
|
|
1835
|
+
border: "1px solid",
|
|
1836
|
+
borderColor: "primary.main",
|
|
1837
|
+
bgcolor: styles.alpha(theme.palette.primary.main, 0.12),
|
|
1838
|
+
borderRadius: 0.5,
|
|
1839
|
+
boxShadow: `0 0 0 1px ${styles.alpha(theme.palette.primary.main, 0.4)}`,
|
|
1840
|
+
transition: "all 60ms linear"
|
|
1841
|
+
}
|
|
1476
1842
|
}
|
|
1477
1843
|
),
|
|
1478
1844
|
hover && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1479
|
-
|
|
1845
|
+
Box6__default.default,
|
|
1480
1846
|
{
|
|
1481
|
-
|
|
1482
|
-
|
|
1847
|
+
sx: {
|
|
1848
|
+
position: "fixed",
|
|
1483
1849
|
top: flipY ? void 0 : hover.y + 14,
|
|
1484
1850
|
bottom: flipY ? window.innerHeight - hover.y + 14 : void 0,
|
|
1485
1851
|
left: flipX ? void 0 : hover.x + 14,
|
|
1486
|
-
right: flipX ? window.innerWidth - hover.x + 14 : void 0
|
|
1852
|
+
right: flipX ? window.innerWidth - hover.x + 14 : void 0,
|
|
1853
|
+
maxWidth: TOOLTIP_W,
|
|
1854
|
+
px: 1.25,
|
|
1855
|
+
py: 1,
|
|
1856
|
+
borderRadius: 1.5,
|
|
1857
|
+
border: "1px solid",
|
|
1858
|
+
borderColor: styles.alpha(theme.palette.common.white, 0.12),
|
|
1859
|
+
bgcolor: styles.alpha(theme.palette.grey[900], 0.85),
|
|
1860
|
+
backdropFilter: "blur(8px)",
|
|
1861
|
+
boxShadow: "0 8px 28px rgba(0,0,0,0.45)",
|
|
1862
|
+
color: theme.palette.common.white
|
|
1487
1863
|
},
|
|
1488
1864
|
children: [
|
|
1489
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1490
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1491
|
-
|
|
1865
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Stack__default.default, { direction: "row", alignItems: "center", spacing: 0.75, sx: { mb: hover.filePath ? 0.5 : 0 }, children: [
|
|
1866
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1867
|
+
Chip__default.default,
|
|
1868
|
+
{
|
|
1869
|
+
label: hover.name,
|
|
1870
|
+
size: "small",
|
|
1871
|
+
sx: { height: 18, fontWeight: 700, fontSize: "0.65rem", color: "#fff", bgcolor: styles.alpha(theme.palette.primary.main, 0.5) }
|
|
1872
|
+
}
|
|
1873
|
+
),
|
|
1874
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography__default.default, { variant: "caption", sx: { color: styles.alpha(theme.palette.common.white, 0.6), fontFamily: "monospace" }, children: `<${hover.domTag}>` })
|
|
1492
1875
|
] }),
|
|
1493
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1494
|
-
hover.route && /* @__PURE__ */ jsxRuntime.jsx("
|
|
1495
|
-
/* @__PURE__ */ jsxRuntime.jsx("
|
|
1876
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography__default.default, { variant: "caption", sx: { display: "block", fontFamily: "monospace", fontSize: "0.68rem", wordBreak: "break-all", color: hover.filePath ? styles.alpha(theme.palette.common.white, 0.85) : styles.alpha(theme.palette.warning.light, 0.9) }, children: hover.filePath ? `${hover.filePath}${hover.line ? `:${hover.line}` : ""}` : "source resolved from graph on lock" }),
|
|
1877
|
+
hover.route && /* @__PURE__ */ jsxRuntime.jsx(Typography__default.default, { variant: "caption", sx: { display: "block", fontSize: "0.62rem", color: styles.alpha(theme.palette.common.white, 0.45) }, children: hover.route }),
|
|
1878
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography__default.default, { variant: "caption", sx: { display: "block", mt: 0.5, fontSize: "0.6rem", color: styles.alpha(theme.palette.common.white, 0.5) }, children: "click to lock \xB7 \u2318/Ctrl + click to open \xB7 Esc to exit" })
|
|
1496
1879
|
]
|
|
1497
1880
|
}
|
|
1498
1881
|
),
|
|
1499
1882
|
state2.toast && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1500
|
-
|
|
1883
|
+
Box6__default.default,
|
|
1501
1884
|
{
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1885
|
+
sx: {
|
|
1886
|
+
position: "fixed",
|
|
1887
|
+
bottom: 24,
|
|
1888
|
+
left: "50%",
|
|
1889
|
+
transform: "translateX(-50%)",
|
|
1890
|
+
px: 1.5,
|
|
1891
|
+
py: 0.75,
|
|
1892
|
+
borderRadius: 1.5,
|
|
1893
|
+
border: "1px solid",
|
|
1894
|
+
borderColor: styles.alpha(theme.palette.common.white, 0.12),
|
|
1895
|
+
bgcolor: styles.alpha(theme.palette.grey[900], 0.9),
|
|
1896
|
+
backdropFilter: "blur(8px)",
|
|
1897
|
+
boxShadow: "0 8px 28px rgba(0,0,0,0.45)"
|
|
1505
1898
|
},
|
|
1506
|
-
children:
|
|
1899
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1900
|
+
Typography__default.default,
|
|
1901
|
+
{
|
|
1902
|
+
variant: "caption",
|
|
1903
|
+
sx: { fontWeight: 600, color: state2.toast.tone === "success" ? "success.light" : state2.toast.tone === "error" ? "error.light" : "common.white" },
|
|
1904
|
+
children: state2.toast.message
|
|
1905
|
+
}
|
|
1906
|
+
)
|
|
1507
1907
|
}
|
|
1508
1908
|
)
|
|
1509
1909
|
] });
|
|
@@ -1513,191 +1913,237 @@ var componentGraphTool = {
|
|
|
1513
1913
|
title: "Component Graph Inspector",
|
|
1514
1914
|
subtitle: "Inspect component tree & open source files",
|
|
1515
1915
|
color: "primary",
|
|
1516
|
-
icon: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1916
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(lu.LuWorkflow, { size: 19 }),
|
|
1517
1917
|
Panel: ComponentGraphPanel,
|
|
1518
1918
|
Overlay: ComponentGraphOverlay
|
|
1519
1919
|
};
|
|
1520
1920
|
function registerComponentGraph() {
|
|
1521
1921
|
registerTool(componentGraphTool);
|
|
1522
1922
|
}
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1923
|
+
function ToolTile({ color, size = 38, children }) {
|
|
1924
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1925
|
+
Box6__default.default,
|
|
1926
|
+
{
|
|
1927
|
+
sx: (theme) => ({
|
|
1928
|
+
width: size,
|
|
1929
|
+
height: size,
|
|
1930
|
+
flexShrink: 0,
|
|
1931
|
+
borderRadius: 1.5,
|
|
1932
|
+
display: "grid",
|
|
1933
|
+
placeItems: "center",
|
|
1934
|
+
color: theme.palette[color].main,
|
|
1935
|
+
bgcolor: styles.alpha(theme.palette[color].main, 0.14)
|
|
1936
|
+
}),
|
|
1937
|
+
children
|
|
1938
|
+
}
|
|
1939
|
+
);
|
|
1940
|
+
}
|
|
1941
|
+
var STORAGE_KEY2 = "react-dev-panel:corner";
|
|
1942
|
+
var EDGE_GAP = 24;
|
|
1943
|
+
var FAB_SIZE = 56;
|
|
1526
1944
|
var DRAG_THRESHOLD = 5;
|
|
1527
1945
|
function isCorner(v) {
|
|
1528
1946
|
return v === "top-left" || v === "top-right" || v === "bottom-left" || v === "bottom-right";
|
|
1529
1947
|
}
|
|
1530
|
-
function
|
|
1948
|
+
function readStoredCorner() {
|
|
1531
1949
|
if (typeof window === "undefined") return "bottom-right";
|
|
1532
1950
|
try {
|
|
1533
|
-
const
|
|
1534
|
-
if (isCorner(
|
|
1951
|
+
const stored = window.localStorage.getItem(STORAGE_KEY2);
|
|
1952
|
+
if (isCorner(stored)) return stored;
|
|
1535
1953
|
} catch {
|
|
1536
1954
|
}
|
|
1537
1955
|
return "bottom-right";
|
|
1538
1956
|
}
|
|
1539
1957
|
function useDraggableCorner() {
|
|
1540
1958
|
const [corner, setCorner] = react.useState("bottom-right");
|
|
1541
|
-
const [
|
|
1542
|
-
const
|
|
1543
|
-
const
|
|
1544
|
-
react.useEffect(() => setCorner(
|
|
1545
|
-
const onPointerDown = react.useCallback((
|
|
1546
|
-
if (
|
|
1547
|
-
const rect =
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
const
|
|
1551
|
-
const
|
|
1552
|
-
const
|
|
1553
|
-
if (!
|
|
1554
|
-
|
|
1555
|
-
|
|
1959
|
+
const [dragPos, setDragPos] = react.useState(null);
|
|
1960
|
+
const movedRef = react.useRef(false);
|
|
1961
|
+
const offsetRef = react.useRef({ x: 0, y: 0 });
|
|
1962
|
+
react.useEffect(() => setCorner(readStoredCorner()), []);
|
|
1963
|
+
const onPointerDown = react.useCallback((event) => {
|
|
1964
|
+
if (event.button !== 0) return;
|
|
1965
|
+
const rect = event.currentTarget.getBoundingClientRect();
|
|
1966
|
+
offsetRef.current = { x: event.clientX - rect.left, y: event.clientY - rect.top };
|
|
1967
|
+
movedRef.current = false;
|
|
1968
|
+
const startX = event.clientX;
|
|
1969
|
+
const startY = event.clientY;
|
|
1970
|
+
const handleMove = (ev) => {
|
|
1971
|
+
if (!movedRef.current && Math.hypot(ev.clientX - startX, ev.clientY - startY) < DRAG_THRESHOLD) return;
|
|
1972
|
+
movedRef.current = true;
|
|
1973
|
+
setDragPos({ x: ev.clientX - offsetRef.current.x, y: ev.clientY - offsetRef.current.y });
|
|
1556
1974
|
};
|
|
1557
|
-
const
|
|
1558
|
-
window.removeEventListener("pointermove",
|
|
1559
|
-
window.removeEventListener("pointerup",
|
|
1560
|
-
if (
|
|
1561
|
-
const
|
|
1562
|
-
const
|
|
1563
|
-
const next = `${
|
|
1975
|
+
const handleUp = (ev) => {
|
|
1976
|
+
window.removeEventListener("pointermove", handleMove);
|
|
1977
|
+
window.removeEventListener("pointerup", handleUp);
|
|
1978
|
+
if (movedRef.current) {
|
|
1979
|
+
const cx = ev.clientX - offsetRef.current.x + FAB_SIZE / 2;
|
|
1980
|
+
const cy = ev.clientY - offsetRef.current.y + FAB_SIZE / 2;
|
|
1981
|
+
const next = `${cy < window.innerHeight / 2 ? "top" : "bottom"}-${cx < window.innerWidth / 2 ? "left" : "right"}`;
|
|
1564
1982
|
setCorner(next);
|
|
1565
1983
|
try {
|
|
1566
|
-
window.localStorage.setItem(
|
|
1984
|
+
window.localStorage.setItem(STORAGE_KEY2, next);
|
|
1567
1985
|
} catch {
|
|
1568
1986
|
}
|
|
1569
1987
|
}
|
|
1570
|
-
|
|
1988
|
+
setDragPos(null);
|
|
1571
1989
|
};
|
|
1572
|
-
window.addEventListener("pointermove",
|
|
1573
|
-
window.addEventListener("pointerup",
|
|
1990
|
+
window.addEventListener("pointermove", handleMove);
|
|
1991
|
+
window.addEventListener("pointerup", handleUp);
|
|
1574
1992
|
}, []);
|
|
1575
|
-
const onClickCapture = react.useCallback((
|
|
1576
|
-
if (
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1993
|
+
const onClickCapture = react.useCallback((event) => {
|
|
1994
|
+
if (movedRef.current) {
|
|
1995
|
+
event.stopPropagation();
|
|
1996
|
+
event.preventDefault();
|
|
1997
|
+
movedRef.current = false;
|
|
1580
1998
|
}
|
|
1581
1999
|
}, []);
|
|
2000
|
+
const dragging = dragPos !== null;
|
|
1582
2001
|
const isTop = corner.startsWith("top");
|
|
1583
2002
|
const isLeft = corner.endsWith("left");
|
|
1584
|
-
const
|
|
1585
|
-
top: isTop ?
|
|
1586
|
-
bottom: isTop ?
|
|
1587
|
-
left: isLeft ?
|
|
1588
|
-
right: isLeft ?
|
|
2003
|
+
const positionSx = dragging ? { top: dragPos.y, left: dragPos.x, right: "auto", bottom: "auto" } : {
|
|
2004
|
+
top: isTop ? EDGE_GAP : "auto",
|
|
2005
|
+
bottom: isTop ? "auto" : EDGE_GAP,
|
|
2006
|
+
left: isLeft ? EDGE_GAP : "auto",
|
|
2007
|
+
right: isLeft ? "auto" : EDGE_GAP
|
|
1589
2008
|
};
|
|
1590
|
-
return {
|
|
2009
|
+
return { positionSx, onPointerDown, onClickCapture, isTop, isLeft, dragging };
|
|
1591
2010
|
}
|
|
1592
2011
|
function ToolBadge({ tool }) {
|
|
1593
2012
|
const badge = tool.useBadge?.();
|
|
1594
2013
|
if (!badge) return null;
|
|
1595
|
-
const
|
|
1596
|
-
|
|
1597
|
-
|
|
2014
|
+
const color = badge.tone === "error" ? "error" : badge.tone === "success" ? "success" : "default";
|
|
2015
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2016
|
+
Chip__default.default,
|
|
2017
|
+
{
|
|
2018
|
+
size: "small",
|
|
2019
|
+
variant: "soft",
|
|
2020
|
+
color,
|
|
2021
|
+
label: badge.label,
|
|
2022
|
+
sx: { height: 18, fontWeight: 700, fontSize: "0.65rem", "& .MuiChip-label": { px: 0.75 } }
|
|
2023
|
+
}
|
|
2024
|
+
);
|
|
1598
2025
|
}
|
|
1599
|
-
function Launcher({
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
}) {
|
|
1603
|
-
const { pos, isTop, isLeft, onPointerDown, onClickCapture } = useDraggableCorner();
|
|
1604
|
-
const [menuOpen, setMenuOpen] = react.useState(false);
|
|
1605
|
-
const menuPos = {
|
|
1606
|
-
top: isTop ? pos.top !== void 0 ? pos.top + FAB + 8 : GAP + FAB + 8 : void 0,
|
|
1607
|
-
bottom: isTop ? void 0 : GAP + FAB + 8,
|
|
1608
|
-
left: isLeft ? GAP : void 0,
|
|
1609
|
-
right: isLeft ? void 0 : GAP
|
|
1610
|
-
};
|
|
2026
|
+
function Launcher({ tools: tools2, onOpenTool }) {
|
|
2027
|
+
const { positionSx, onPointerDown, onClickCapture, isTop, isLeft, dragging } = useDraggableCorner();
|
|
2028
|
+
const [menuAnchor, setMenuAnchor] = react.useState(null);
|
|
1611
2029
|
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1612
2030
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1613
|
-
|
|
2031
|
+
Box6__default.default,
|
|
1614
2032
|
{
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
2033
|
+
"data-rdp-ignore": "",
|
|
2034
|
+
sx: (theme) => ({ position: "fixed", zIndex: theme.zIndex.modal + 2, ...positionSx }),
|
|
2035
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(Tooltip2__default.default, { title: dragging ? "" : "Developer Tools \u2014 drag to a corner", placement: isLeft ? "right" : "left", arrow: true, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2036
|
+
Fab__default.default,
|
|
2037
|
+
{
|
|
2038
|
+
onClick: (e) => setMenuAnchor(e.currentTarget),
|
|
2039
|
+
onClickCapture,
|
|
2040
|
+
onPointerDown,
|
|
2041
|
+
"aria-label": "Open Developer Tools",
|
|
2042
|
+
"aria-haspopup": "menu",
|
|
2043
|
+
sx: (theme) => ({
|
|
2044
|
+
width: FAB_SIZE,
|
|
2045
|
+
height: FAB_SIZE,
|
|
2046
|
+
touchAction: "none",
|
|
2047
|
+
cursor: dragging ? "grabbing" : "grab",
|
|
2048
|
+
color: theme.palette.primary.contrastText,
|
|
2049
|
+
background: `linear-gradient(135deg, ${theme.palette.primary.main}, ${theme.palette.primary.dark})`,
|
|
2050
|
+
boxShadow: `0 4px 12px ${styles.alpha(theme.palette.primary.main, 0.24)}, 0 8px 24px rgba(0,0,0,0.5)`,
|
|
2051
|
+
"&:hover": {
|
|
2052
|
+
background: `linear-gradient(135deg, ${theme.palette.primary.dark}, ${theme.palette.primary.dark})`
|
|
2053
|
+
}
|
|
2054
|
+
}),
|
|
2055
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lu.LuWrench, { size: 22 })
|
|
2056
|
+
}
|
|
2057
|
+
) })
|
|
1624
2058
|
}
|
|
1625
2059
|
),
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
}
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
className: "rdp-row",
|
|
1648
|
-
role: "menuitem",
|
|
1649
|
-
onClick: () => {
|
|
1650
|
-
onOpenTool(tool.id);
|
|
1651
|
-
setMenuOpen(false);
|
|
1652
|
-
},
|
|
1653
|
-
children: [
|
|
1654
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1655
|
-
"span",
|
|
1656
|
-
{
|
|
1657
|
-
className: "rdp-tile",
|
|
1658
|
-
style: { color: colorVar(tool.color), background: "rgba(148,163,184,0.1)" },
|
|
1659
|
-
children: tool.icon
|
|
1660
|
-
}
|
|
1661
|
-
),
|
|
1662
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", { style: { flex: 1, minWidth: 0 }, children: [
|
|
1663
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "rdp-title", style: { display: "block" }, children: tool.title }),
|
|
1664
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "rdp-sub", style: { display: "block" }, children: tool.subtitle })
|
|
1665
|
-
] }),
|
|
1666
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", { style: { display: "inline-flex", alignItems: "center", gap: 6, color: "var(--rdp-text-faint)" }, children: [
|
|
1667
|
-
/* @__PURE__ */ jsxRuntime.jsx(ToolBadge, { tool }),
|
|
1668
|
-
/* @__PURE__ */ jsxRuntime.jsx(IconChevronRight, { size: 16 })
|
|
1669
|
-
] })
|
|
1670
|
-
]
|
|
2060
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2061
|
+
Menu__default.default,
|
|
2062
|
+
{
|
|
2063
|
+
anchorEl: menuAnchor,
|
|
2064
|
+
open: Boolean(menuAnchor),
|
|
2065
|
+
onClose: () => setMenuAnchor(null),
|
|
2066
|
+
sx: (theme) => ({ zIndex: theme.zIndex.modal + 2 }),
|
|
2067
|
+
anchorOrigin: { vertical: isTop ? "bottom" : "top", horizontal: isLeft ? "left" : "right" },
|
|
2068
|
+
transformOrigin: { vertical: isTop ? "top" : "bottom", horizontal: isLeft ? "left" : "right" },
|
|
2069
|
+
slotProps: {
|
|
2070
|
+
paper: {
|
|
2071
|
+
sx: {
|
|
2072
|
+
width: 320,
|
|
2073
|
+
mt: isTop ? 1.5 : 0,
|
|
2074
|
+
mb: isTop ? 0 : 1.5,
|
|
2075
|
+
borderRadius: 2.5,
|
|
2076
|
+
overflow: "hidden",
|
|
2077
|
+
border: "1px solid",
|
|
2078
|
+
borderColor: "divider",
|
|
2079
|
+
boxShadow: 16
|
|
2080
|
+
}
|
|
1671
2081
|
},
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
2082
|
+
list: { sx: { py: 0 } }
|
|
2083
|
+
},
|
|
2084
|
+
children: [
|
|
2085
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2086
|
+
Box6__default.default,
|
|
2087
|
+
{
|
|
2088
|
+
sx: {
|
|
2089
|
+
display: "flex",
|
|
2090
|
+
alignItems: "center",
|
|
2091
|
+
gap: 1.25,
|
|
2092
|
+
px: 2,
|
|
2093
|
+
py: 1.5,
|
|
2094
|
+
background: (theme) => `linear-gradient(135deg, ${styles.alpha(theme.palette.primary.main, 0.16)}, ${styles.alpha(theme.palette.primary.main, 0.04)})`
|
|
2095
|
+
},
|
|
2096
|
+
children: [
|
|
2097
|
+
/* @__PURE__ */ jsxRuntime.jsx(ToolTile, { color: "primary", size: 34, children: /* @__PURE__ */ jsxRuntime.jsx(lu.LuWrench, { size: 17 }) }),
|
|
2098
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Box6__default.default, { sx: { minWidth: 0 }, children: [
|
|
2099
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography__default.default, { variant: "subtitle2", sx: { fontWeight: 700, lineHeight: 1.2 }, children: "Developer Tools" }),
|
|
2100
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography__default.default, { variant: "caption", sx: { color: "text.secondary" }, children: "Internal utilities" })
|
|
2101
|
+
] })
|
|
2102
|
+
]
|
|
2103
|
+
}
|
|
2104
|
+
),
|
|
2105
|
+
/* @__PURE__ */ jsxRuntime.jsx(Divider__default.default, {}),
|
|
2106
|
+
/* @__PURE__ */ jsxRuntime.jsx(Box6__default.default, { sx: { p: 1 }, children: tools2.map((tool, i) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2107
|
+
MenuItem__default.default,
|
|
2108
|
+
{
|
|
2109
|
+
onClick: () => {
|
|
2110
|
+
onOpenTool(tool.id);
|
|
2111
|
+
setMenuAnchor(null);
|
|
2112
|
+
},
|
|
2113
|
+
disableGutters: true,
|
|
2114
|
+
sx: { alignItems: "flex-start", gap: 1.25, px: 1.25, py: 1.25, mt: i === 0 ? 0 : 0.5, borderRadius: 1.5, whiteSpace: "normal" },
|
|
2115
|
+
children: [
|
|
2116
|
+
/* @__PURE__ */ jsxRuntime.jsx(ToolTile, { color: tool.color ?? "primary", children: tool.icon }),
|
|
2117
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Box6__default.default, { sx: { flex: 1, minWidth: 0 }, children: [
|
|
2118
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography__default.default, { variant: "subtitle2", sx: { fontWeight: 600, lineHeight: 1.3 }, children: tool.title }),
|
|
2119
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography__default.default, { variant: "caption", sx: { color: "text.secondary", display: "block" }, children: tool.subtitle })
|
|
2120
|
+
] }),
|
|
2121
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Stack__default.default, { direction: "row", spacing: 0.5, alignItems: "center", sx: { mt: 0.25 }, children: [
|
|
2122
|
+
/* @__PURE__ */ jsxRuntime.jsx(ToolBadge, { tool }),
|
|
2123
|
+
/* @__PURE__ */ jsxRuntime.jsx(Box6__default.default, { sx: { display: "grid", placeItems: "center", color: "text.disabled" }, children: /* @__PURE__ */ jsxRuntime.jsx(lu.LuChevronRight, { size: 16 }) })
|
|
2124
|
+
] })
|
|
2125
|
+
]
|
|
2126
|
+
},
|
|
2127
|
+
tool.id
|
|
2128
|
+
)) })
|
|
2129
|
+
]
|
|
2130
|
+
}
|
|
2131
|
+
)
|
|
1676
2132
|
] });
|
|
1677
2133
|
}
|
|
1678
2134
|
function DevPanel(config) {
|
|
1679
2135
|
const enabled = config.enabled ?? (typeof process !== "undefined" ? process.env.NODE_ENV !== "production" : true);
|
|
1680
|
-
react.useEffect(() => {
|
|
1681
|
-
if (enabled) injectBaseStyles();
|
|
1682
|
-
}, [enabled]);
|
|
1683
2136
|
if (!enabled) return null;
|
|
1684
|
-
return /* @__PURE__ */ jsxRuntime.jsx(DevPanelConfigProvider, { config, children: /* @__PURE__ */ jsxRuntime.jsx(DevPanelInner, { ids: config.tools
|
|
2137
|
+
return /* @__PURE__ */ jsxRuntime.jsx(DevPanelConfigProvider, { config, children: /* @__PURE__ */ jsxRuntime.jsx(DevPanelInner, { ids: config.tools }) });
|
|
1685
2138
|
}
|
|
1686
|
-
function DevPanelInner({
|
|
1687
|
-
ids,
|
|
1688
|
-
theme
|
|
1689
|
-
}) {
|
|
2139
|
+
function DevPanelInner({ ids }) {
|
|
1690
2140
|
const tools2 = react.useMemo(() => resolveTools(ids), [ids]);
|
|
1691
2141
|
const [openId, setOpenId] = react.useState(null);
|
|
1692
2142
|
react.useEffect(() => {
|
|
1693
2143
|
tools2.forEach((t) => t.init?.());
|
|
1694
2144
|
}, [tools2]);
|
|
1695
|
-
const rootStyle = {};
|
|
1696
|
-
if (theme?.accent) rootStyle["--rdp-accent"] = theme.accent;
|
|
1697
|
-
if (theme?.accentContrast)
|
|
1698
|
-
rootStyle["--rdp-accent-contrast"] = theme.accentContrast;
|
|
1699
2145
|
const ActivePanel = tools2.find((t) => t.id === openId)?.Panel ?? null;
|
|
1700
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2146
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1701
2147
|
/* @__PURE__ */ jsxRuntime.jsx(Launcher, { tools: tools2, onOpenTool: setOpenId }),
|
|
1702
2148
|
ActivePanel && /* @__PURE__ */ jsxRuntime.jsx(ActivePanel, { onClose: () => setOpenId(null) }),
|
|
1703
2149
|
tools2.map((t) => t.Overlay ? /* @__PURE__ */ jsxRuntime.jsx(t.Overlay, {}, t.id) : null)
|
|
@@ -1737,7 +2183,6 @@ exports.DevPanel = DevPanel;
|
|
|
1737
2183
|
exports.createServerOpenInEditor = createServerOpenInEditor;
|
|
1738
2184
|
exports.defaultOpenInEditor = defaultOpenInEditor;
|
|
1739
2185
|
exports.getRegisteredTools = getRegisteredTools;
|
|
1740
|
-
exports.injectBaseStyles = injectBaseStyles;
|
|
1741
2186
|
exports.registerTool = registerTool;
|
|
1742
2187
|
exports.serverOpenInEditor = serverOpenInEditor;
|
|
1743
2188
|
exports.useDevPanelConfig = useDevPanelConfig;
|