react-dev-panel 0.1.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +1299 -821
- 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 +1281 -822
- package/dist/index.js.map +1 -1
- package/package.json +11 -2
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 Typography3 = 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 Typography3__default = /*#__PURE__*/_interopDefault(Typography3);
|
|
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
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
56
|
+
function resolveTools(ids) {
|
|
57
|
+
if (!ids || ids.length === 0) return getRegisteredTools();
|
|
58
|
+
return ids.map((id) => tools.get(id)).filter((t) => Boolean(t));
|
|
59
|
+
}
|
|
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
|
+
}
|
|
67
75
|
}
|
|
68
|
-
|
|
69
|
-
|
|
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
|
+
};
|
|
70
102
|
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
.
|
|
77
|
-
display: flex; align-items: flex-start; gap: 12px; padding: 10px 12px;
|
|
78
|
-
border-radius: 8px; cursor: pointer; width: 100%; text-align: left; border: none;
|
|
79
|
-
background: transparent; color: inherit; font: inherit;
|
|
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 });
|
|
80
109
|
}
|
|
81
|
-
|
|
82
|
-
.
|
|
83
|
-
|
|
84
|
-
|
|
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;
|
|
85
114
|
}
|
|
86
115
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
.
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
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;
|
|
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);
|
|
118
136
|
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
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
|
+
}
|
|
270
304
|
}
|
|
271
|
-
function
|
|
272
|
-
|
|
273
|
-
|
|
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
|
+
}
|
|
312
|
+
}
|
|
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(Typography3__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
|
+
)
|
|
654
|
+
] });
|
|
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
|
+
Typography3__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(Typography3__default.default, { variant: "caption", sx: { color: "text.disabled", fontFamily: "monospace" }, children: formatTime(entry.timestamp) }),
|
|
702
|
+
showPath && entry.path && /* @__PURE__ */ jsxRuntime.jsx(Typography3__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)) }) })
|
|
359
710
|
] });
|
|
360
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(Typography3__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(Typography3__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,195 +848,171 @@ 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(Typography3__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(Typography3__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(Typography3__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(Typography3__default.default, { variant: "caption", sx: { color: `${RATING_COLOR[m.rating]}.main`, ml: "auto" }, children: m.rating })
|
|
908
|
+
] }),
|
|
909
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography3__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
|
}
|
|
950
|
+
var EDITORS = [
|
|
951
|
+
{ key: "vscode", label: "VS Code" },
|
|
952
|
+
{ key: "cursor", label: "Cursor" },
|
|
953
|
+
{ key: "webstorm", label: "WebStorm" }
|
|
954
|
+
];
|
|
537
955
|
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
|
-
)) });
|
|
956
|
+
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
957
|
}
|
|
550
958
|
function Row({ label, children }) {
|
|
551
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
552
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
553
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
959
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(Stack__default.default, { direction: "row", spacing: 1, sx: { mt: 0.5 }, children: [
|
|
960
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography3__default.default, { variant: "caption", sx: { minWidth: 56, color: "text.disabled", fontWeight: 600, flexShrink: 0 }, children: label }),
|
|
961
|
+
/* @__PURE__ */ jsxRuntime.jsx(Box6__default.default, { sx: { minWidth: 0, flex: 1 }, children })
|
|
554
962
|
] });
|
|
555
963
|
}
|
|
556
964
|
function NodeDetails({
|
|
557
965
|
selected,
|
|
966
|
+
editor,
|
|
558
967
|
onOpen,
|
|
968
|
+
onOpenEditor,
|
|
559
969
|
onCopyInfo,
|
|
560
970
|
onCopyPath,
|
|
561
971
|
onSelectName
|
|
562
972
|
}) {
|
|
563
973
|
if (!selected) {
|
|
564
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
974
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Typography3__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
975
|
}
|
|
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
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
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
|
-
);
|
|
976
|
+
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: [
|
|
977
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Stack__default.default, { direction: "row", alignItems: "center", spacing: 0.75, children: [
|
|
978
|
+
/* @__PURE__ */ jsxRuntime.jsx(Chip__default.default, { label: selected.componentName, size: "small", color: "primary", variant: "soft", sx: { height: 20, fontSize: "0.68rem", fontWeight: 700 } }),
|
|
979
|
+
selected.domTag && /* @__PURE__ */ jsxRuntime.jsx(Typography3__default.default, { variant: "caption", sx: { color: "text.disabled", fontFamily: "monospace" }, children: `<${selected.domTag}>` })
|
|
980
|
+
] }),
|
|
981
|
+
selected.filePath ? /* @__PURE__ */ jsxRuntime.jsxs(Typography3__default.default, { variant: "caption", sx: { display: "block", mt: 0.75, fontFamily: "monospace", fontSize: "0.68rem", wordBreak: "break-all", color: "text.secondary" }, children: [
|
|
982
|
+
selected.filePath,
|
|
983
|
+
selected.line ? `:${selected.line}` : "",
|
|
984
|
+
selected.line && selected.column ? `:${selected.column}` : ""
|
|
985
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsx(Typography3__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." }),
|
|
986
|
+
selected.route && /* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Route", children: /* @__PURE__ */ jsxRuntime.jsx(Typography3__default.default, { variant: "caption", sx: { fontFamily: "monospace" }, children: selected.route }) }),
|
|
987
|
+
selected.parent && /* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Parent", children: /* @__PURE__ */ jsxRuntime.jsx(Chips, { names: [selected.parent], onSelect: onSelectName }) }),
|
|
988
|
+
selected.children.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Renders", children: /* @__PURE__ */ jsxRuntime.jsx(Chips, { names: selected.children, onSelect: onSelectName }) }),
|
|
989
|
+
selected.imports.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(Row, { label: "Imports", children: /* @__PURE__ */ jsxRuntime.jsx(Chips, { names: selected.imports, onSelect: onSelectName }) }),
|
|
990
|
+
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: [
|
|
991
|
+
/* @__PURE__ */ jsxRuntime.jsx(Box6__default.default, { component: "span", sx: { color: "primary.main" }, children: p.name }),
|
|
992
|
+
"=",
|
|
993
|
+
p.value
|
|
994
|
+
] }, p.name)) }) }),
|
|
995
|
+
/* @__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" }),
|
|
996
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Stack__default.default, { direction: "row", alignItems: "center", spacing: 0.5, useFlexGap: true, sx: { flexWrap: "wrap", mt: 0.75 }, children: [
|
|
997
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography3__default.default, { variant: "caption", sx: { color: "text.disabled" }, children: "force:" }),
|
|
998
|
+
EDITORS.map((opt) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
999
|
+
Button__default.default,
|
|
1000
|
+
{
|
|
1001
|
+
size: "small",
|
|
1002
|
+
variant: opt.key === editor ? "contained" : "text",
|
|
1003
|
+
startIcon: /* @__PURE__ */ jsxRuntime.jsx(lu.LuLink, { size: 12 }),
|
|
1004
|
+
onClick: () => onOpenEditor(opt.key),
|
|
1005
|
+
sx: { textTransform: "none", fontSize: "0.66rem", py: 0.1, minWidth: 0 },
|
|
1006
|
+
children: opt.label
|
|
1007
|
+
},
|
|
1008
|
+
opt.key
|
|
1009
|
+
))
|
|
1010
|
+
] }),
|
|
1011
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Stack__default.default, { direction: "row", spacing: 1, sx: { mt: 1 }, children: [
|
|
1012
|
+
/* @__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 }) }) }),
|
|
1013
|
+
/* @__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 }) }) }) })
|
|
1014
|
+
] })
|
|
1015
|
+
] });
|
|
615
1016
|
}
|
|
616
1017
|
|
|
617
1018
|
// src/tools/component-graph/graph-utils.ts
|
|
@@ -878,27 +1279,23 @@ function formatForCopy(s) {
|
|
|
878
1279
|
}
|
|
879
1280
|
var MAX_DEPTH = 6;
|
|
880
1281
|
function Label({ children }) {
|
|
881
|
-
return /* @__PURE__ */ jsxRuntime.jsx("
|
|
1282
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Typography3__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
1283
|
}
|
|
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) => {
|
|
1284
|
+
function RowActions({ node, onOpen, onCopy }) {
|
|
1285
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1286
|
+
/* @__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
1287
|
e.stopPropagation();
|
|
891
1288
|
onOpen(node);
|
|
892
|
-
}, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
893
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1289
|
+
}, children: /* @__PURE__ */ jsxRuntime.jsx(lu.LuFileCode, { size: 13 }) }) }),
|
|
1290
|
+
/* @__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
1291
|
e.stopPropagation();
|
|
895
1292
|
onCopy(node);
|
|
896
|
-
}, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1293
|
+
}, children: /* @__PURE__ */ jsxRuntime.jsx(lu.LuCopy, { size: 13 }) }) })
|
|
897
1294
|
] });
|
|
898
1295
|
}
|
|
899
1296
|
function RowShell({
|
|
900
1297
|
depth = 0,
|
|
901
|
-
active,
|
|
1298
|
+
active = false,
|
|
902
1299
|
caret,
|
|
903
1300
|
label,
|
|
904
1301
|
isRoute,
|
|
@@ -906,42 +1303,43 @@ function RowShell({
|
|
|
906
1303
|
actions
|
|
907
1304
|
}) {
|
|
908
1305
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
909
|
-
|
|
1306
|
+
Stack__default.default,
|
|
910
1307
|
{
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
1308
|
+
direction: "row",
|
|
1309
|
+
alignItems: "center",
|
|
1310
|
+
spacing: 0.5,
|
|
1311
|
+
sx: (t) => ({
|
|
1312
|
+
pl: 0.5 + depth * 1.5,
|
|
1313
|
+
pr: 0.5,
|
|
1314
|
+
py: 0.25,
|
|
1315
|
+
borderRadius: 1,
|
|
1316
|
+
bgcolor: active ? styles.alpha(t.palette.primary.main, 0.16) : "transparent",
|
|
1317
|
+
"&:hover": { bgcolor: active ? styles.alpha(t.palette.primary.main, 0.2) : "action.hover" },
|
|
1318
|
+
"&:hover .rdp-row-actions": { opacity: 1 }
|
|
1319
|
+
}),
|
|
919
1320
|
children: [
|
|
920
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1321
|
+
/* @__PURE__ */ jsxRuntime.jsx(Box6__default.default, { sx: { width: 16, display: "grid", placeItems: "center", color: "text.disabled" }, children: caret }),
|
|
921
1322
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
922
|
-
|
|
1323
|
+
Typography3__default.default,
|
|
923
1324
|
{
|
|
924
|
-
type: "button",
|
|
925
1325
|
onClick: onLabel,
|
|
926
|
-
|
|
927
|
-
|
|
1326
|
+
variant: "caption",
|
|
1327
|
+
sx: {
|
|
928
1328
|
flex: 1,
|
|
929
1329
|
minWidth: 0,
|
|
930
|
-
textAlign: "left",
|
|
931
|
-
background: "none",
|
|
932
|
-
border: "none",
|
|
933
1330
|
cursor: "pointer",
|
|
934
|
-
fontSize: 12,
|
|
935
1331
|
fontWeight: active ? 700 : 500,
|
|
936
|
-
|
|
937
|
-
|
|
1332
|
+
fontFamily: "monospace",
|
|
1333
|
+
fontSize: "0.72rem",
|
|
938
1334
|
overflow: "hidden",
|
|
939
|
-
textOverflow: "ellipsis"
|
|
1335
|
+
textOverflow: "ellipsis",
|
|
1336
|
+
whiteSpace: "nowrap",
|
|
1337
|
+
color: isRoute ? "info.main" : active ? "primary.main" : "text.primary"
|
|
940
1338
|
},
|
|
941
1339
|
children: label
|
|
942
1340
|
}
|
|
943
1341
|
),
|
|
944
|
-
actions
|
|
1342
|
+
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
1343
|
]
|
|
946
1344
|
}
|
|
947
1345
|
);
|
|
@@ -953,14 +1351,14 @@ function Branch({ name, depth, trail, p }) {
|
|
|
953
1351
|
const hasKids = kids.length > 0 && depth < MAX_DEPTH && !trail.has(id);
|
|
954
1352
|
const open = p.expanded.has(id);
|
|
955
1353
|
const active = p.selected?.nodeId === id || p.selected?.componentName === name;
|
|
956
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1354
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(Box6__default.default, { children: [
|
|
957
1355
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
958
1356
|
RowShell,
|
|
959
1357
|
{
|
|
960
1358
|
depth,
|
|
961
1359
|
active,
|
|
962
1360
|
isRoute: node?.type === "route",
|
|
963
|
-
caret: hasKids ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1361
|
+
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
1362
|
label: name,
|
|
965
1363
|
onLabel: () => node && p.onSelect(node),
|
|
966
1364
|
actions: node ? /* @__PURE__ */ jsxRuntime.jsx(RowActions, { node, onOpen: p.onOpen, onCopy: p.onCopy }) : null
|
|
@@ -973,7 +1371,7 @@ function ComponentGraphTree(p) {
|
|
|
973
1371
|
const { graph, selected, search } = p;
|
|
974
1372
|
if (graph && search.trim()) {
|
|
975
1373
|
const results = searchNodes(graph, search);
|
|
976
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1374
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(Box6__default.default, { children: [
|
|
977
1375
|
/* @__PURE__ */ jsxRuntime.jsxs(Label, { children: [
|
|
978
1376
|
results.length,
|
|
979
1377
|
" match",
|
|
@@ -990,7 +1388,7 @@ function ComponentGraphTree(p) {
|
|
|
990
1388
|
},
|
|
991
1389
|
node.id
|
|
992
1390
|
)),
|
|
993
|
-
results.length === 0 && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1391
|
+
results.length === 0 && /* @__PURE__ */ jsxRuntime.jsxs(Typography3__default.default, { variant: "caption", sx: { color: "text.disabled", pl: 1 }, children: [
|
|
994
1392
|
"No components match \u201C",
|
|
995
1393
|
search,
|
|
996
1394
|
"\u201D."
|
|
@@ -998,9 +1396,9 @@ function ComponentGraphTree(p) {
|
|
|
998
1396
|
] });
|
|
999
1397
|
}
|
|
1000
1398
|
if (!selected) {
|
|
1001
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1399
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Typography3__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
1400
|
}
|
|
1003
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1401
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(Box6__default.default, { children: [
|
|
1004
1402
|
selected.parents.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1005
1403
|
/* @__PURE__ */ jsxRuntime.jsx(Label, { children: "Parent chain" }),
|
|
1006
1404
|
selected.parents.map((parent) => {
|
|
@@ -1009,7 +1407,7 @@ function ComponentGraphTree(p) {
|
|
|
1009
1407
|
RowShell,
|
|
1010
1408
|
{
|
|
1011
1409
|
isRoute: node?.type === "route",
|
|
1012
|
-
caret: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1410
|
+
caret: /* @__PURE__ */ jsxRuntime.jsx(lu.LuArrowUp, { size: 12 }),
|
|
1013
1411
|
label: parent,
|
|
1014
1412
|
onLabel: () => node && p.onSelect(node),
|
|
1015
1413
|
actions: node ? /* @__PURE__ */ jsxRuntime.jsx(RowActions, { node, onOpen: p.onOpen, onCopy: p.onCopy }) : null
|
|
@@ -1019,13 +1417,13 @@ function ComponentGraphTree(p) {
|
|
|
1019
1417
|
})
|
|
1020
1418
|
] }),
|
|
1021
1419
|
/* @__PURE__ */ jsxRuntime.jsx(Label, { children: "Selected" }),
|
|
1022
|
-
/* @__PURE__ */ jsxRuntime.jsx(RowShell, { active: true, label: selected.componentName, onLabel: () => void 0 }),
|
|
1420
|
+
/* @__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
1421
|
/* @__PURE__ */ jsxRuntime.jsxs(Label, { children: [
|
|
1024
1422
|
"Renders (",
|
|
1025
1423
|
selected.children.length,
|
|
1026
1424
|
")"
|
|
1027
1425
|
] }),
|
|
1028
|
-
selected.children.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1426
|
+
selected.children.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(Typography3__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
1427
|
selected.imports.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1030
1428
|
/* @__PURE__ */ jsxRuntime.jsxs(Label, { children: [
|
|
1031
1429
|
"Imports (",
|
|
@@ -1072,56 +1470,60 @@ function ComponentGraphPageList({
|
|
|
1072
1470
|
};
|
|
1073
1471
|
}, [scan, route]);
|
|
1074
1472
|
if (!graph) {
|
|
1075
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1473
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Typography3__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
1474
|
}
|
|
1077
1475
|
const q = query.trim().toLowerCase();
|
|
1078
1476
|
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",
|
|
1477
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(Box6__default.default, { children: [
|
|
1478
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Stack__default.default, { direction: "row", alignItems: "center", justifyContent: "space-between", sx: { mb: 0.5 }, children: [
|
|
1479
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Typography3__default.default, { variant: "caption", sx: { color: "text.secondary" }, children: [
|
|
1480
|
+
/* @__PURE__ */ jsxRuntime.jsx(Box6__default.default, { component: "span", sx: { fontFamily: "monospace", color: "info.main" }, children: route ?? "/" }),
|
|
1084
1481
|
" ",
|
|
1482
|
+
"\xB7 ",
|
|
1085
1483
|
q ? `${filtered.length} / ${items.length}` : items.length,
|
|
1086
1484
|
" component",
|
|
1087
1485
|
items.length === 1 ? "" : "s"
|
|
1088
1486
|
] }),
|
|
1089
|
-
/* @__PURE__ */ jsxRuntime.
|
|
1090
|
-
/* @__PURE__ */ jsxRuntime.jsx(IconRefresh, { size: 13 }),
|
|
1091
|
-
" Rescan"
|
|
1092
|
-
] })
|
|
1487
|
+
/* @__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
1488
|
] }),
|
|
1094
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1095
|
-
items.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1489
|
+
/* @__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" }) }),
|
|
1490
|
+
items.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(Typography3__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(Typography3__default.default, { variant: "caption", sx: { color: "text.disabled", pl: 0.5 }, children: [
|
|
1096
1491
|
"No components match \u201C",
|
|
1097
1492
|
query,
|
|
1098
1493
|
"\u201D."
|
|
1099
1494
|
] }) : filtered.map(({ name, node, count }) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1100
|
-
|
|
1495
|
+
Stack__default.default,
|
|
1101
1496
|
{
|
|
1102
|
-
|
|
1103
|
-
|
|
1497
|
+
direction: "row",
|
|
1498
|
+
alignItems: "center",
|
|
1499
|
+
spacing: 0.5,
|
|
1104
1500
|
onClick: () => onSelect(node),
|
|
1501
|
+
sx: (t) => ({
|
|
1502
|
+
px: 0.5,
|
|
1503
|
+
py: 0.4,
|
|
1504
|
+
borderRadius: 1,
|
|
1505
|
+
cursor: "pointer",
|
|
1506
|
+
bgcolor: selectedName === name ? styles.alpha(t.palette.primary.main, 0.16) : "transparent",
|
|
1507
|
+
"&:hover": { bgcolor: "action.hover" },
|
|
1508
|
+
"&:hover .rdp-row-actions": { opacity: 1 }
|
|
1509
|
+
}),
|
|
1105
1510
|
children: [
|
|
1106
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1107
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1108
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1109
|
-
count > 1 && /* @__PURE__ */ jsxRuntime.
|
|
1110
|
-
"\xD7",
|
|
1111
|
-
count
|
|
1112
|
-
] })
|
|
1511
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Box6__default.default, { sx: { flex: 1, minWidth: 0 }, children: [
|
|
1512
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Stack__default.default, { direction: "row", alignItems: "center", spacing: 0.5, children: [
|
|
1513
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography3__default.default, { variant: "caption", sx: { fontFamily: "monospace", fontWeight: 600, fontSize: "0.72rem", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }, children: name }),
|
|
1514
|
+
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
1515
|
] }),
|
|
1114
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1516
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography3__default.default, { variant: "caption", sx: { display: "block", color: "text.disabled", fontSize: "0.62rem", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }, children: node.filePath })
|
|
1115
1517
|
] }),
|
|
1116
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1117
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1518
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Stack__default.default, { direction: "row", spacing: 0.25, className: "rdp-row-actions", sx: { opacity: 0, transition: "opacity 120ms" }, children: [
|
|
1519
|
+
/* @__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
1520
|
e.stopPropagation();
|
|
1119
1521
|
onOpen(node);
|
|
1120
|
-
}, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1121
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1522
|
+
}, children: /* @__PURE__ */ jsxRuntime.jsx(lu.LuFileCode, { size: 13 }) }) }),
|
|
1523
|
+
/* @__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
1524
|
e.stopPropagation();
|
|
1123
1525
|
onCopy(node);
|
|
1124
|
-
}, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1526
|
+
}, children: /* @__PURE__ */ jsxRuntime.jsx(lu.LuCopy, { size: 13 }) }) })
|
|
1125
1527
|
] })
|
|
1126
1528
|
]
|
|
1127
1529
|
},
|
|
@@ -1223,10 +1625,10 @@ function loadGraph(endpoint, force = false) {
|
|
|
1223
1625
|
return graphPromise;
|
|
1224
1626
|
}
|
|
1225
1627
|
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(
|
|
1628
|
+
{ value: "hover", label: "Hover", icon: /* @__PURE__ */ jsxRuntime.jsx(lu.LuMousePointerClick, { size: 14 }) },
|
|
1629
|
+
{ value: "graph", label: "Graph", icon: /* @__PURE__ */ jsxRuntime.jsx(lu.LuWorkflow, { size: 14 }) },
|
|
1630
|
+
{ value: "page", label: "Page", icon: /* @__PURE__ */ jsxRuntime.jsx(lu.LuLayers, { size: 14 }) },
|
|
1631
|
+
{ value: "file", label: "File", icon: /* @__PURE__ */ jsxRuntime.jsx(lu.LuFile, { size: 14 }) }
|
|
1230
1632
|
];
|
|
1231
1633
|
async function copy(text) {
|
|
1232
1634
|
if (typeof navigator === "undefined" || !navigator.clipboard) return false;
|
|
@@ -1237,17 +1639,15 @@ async function copy(text) {
|
|
|
1237
1639
|
}
|
|
1238
1640
|
function ComponentGraphPanel({ onClose }) {
|
|
1239
1641
|
const state2 = react.useSyncExternalStore(subscribeGraph, getGraphState, getGraphServerState);
|
|
1642
|
+
const theme = styles.useTheme();
|
|
1240
1643
|
const config = useDevPanelConfig();
|
|
1241
1644
|
const route = config.getRoute();
|
|
1242
1645
|
const { enabled, mode, selected, graph, status, search, expanded } = state2;
|
|
1243
1646
|
const openLoc = react.useCallback(
|
|
1244
|
-
async (sel) => {
|
|
1647
|
+
async (sel, editor) => {
|
|
1245
1648
|
const file = sel?.absFilePath ?? sel?.filePath;
|
|
1246
|
-
if (!file) {
|
|
1247
|
-
|
|
1248
|
-
return;
|
|
1249
|
-
}
|
|
1250
|
-
const ok = await config.openInEditor?.({ file, line: sel?.line, column: sel?.column }, config.editor);
|
|
1649
|
+
if (!file) return showToast({ message: "No source path available", tone: "error" });
|
|
1650
|
+
const ok = await config.openInEditor?.({ file, line: sel?.line, column: sel?.column }, editor ?? config.editor);
|
|
1251
1651
|
showToast(ok === false ? { message: "Editor unavailable \u2014 path copied", tone: "info" } : { message: "Opening in your editor\u2026", tone: "success" });
|
|
1252
1652
|
},
|
|
1253
1653
|
[config]
|
|
@@ -1256,14 +1656,11 @@ function ComponentGraphPanel({ onClose }) {
|
|
|
1256
1656
|
if (!selected) return;
|
|
1257
1657
|
void copy(formatForCopy(selected)).then((ok) => showToast({ message: ok ? "Component info copied" : "Copy failed", tone: ok ? "success" : "error" }));
|
|
1258
1658
|
}, [selected]);
|
|
1259
|
-
const copyPath = react.useCallback(
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
},
|
|
1265
|
-
[]
|
|
1266
|
-
);
|
|
1659
|
+
const copyPath = react.useCallback((sel) => {
|
|
1660
|
+
const path = sel?.filePath ?? sel?.absFilePath;
|
|
1661
|
+
if (!path) return showToast({ message: "No path to copy", tone: "info" });
|
|
1662
|
+
void copy(`${path}${sel?.line ? `:${sel.line}` : ""}`).then((ok) => showToast({ message: ok ? "File path copied" : "Copy failed", tone: ok ? "success" : "error" }));
|
|
1663
|
+
}, []);
|
|
1267
1664
|
const selectName = react.useCallback(
|
|
1268
1665
|
(name) => {
|
|
1269
1666
|
const node = graph?.nodes.find((n) => n.name === name || n.id === name);
|
|
@@ -1284,126 +1681,120 @@ function ComponentGraphPanel({ onClose }) {
|
|
|
1284
1681
|
NodeDetails,
|
|
1285
1682
|
{
|
|
1286
1683
|
selected,
|
|
1684
|
+
editor: config.editor,
|
|
1287
1685
|
onOpen: () => void openLoc(selected),
|
|
1686
|
+
onOpenEditor: (editor) => void openLoc(selected, editor),
|
|
1288
1687
|
onCopyInfo: copyInfo,
|
|
1289
1688
|
onCopyPath: () => copyPath(selected),
|
|
1290
1689
|
onSelectName: selectName
|
|
1291
1690
|
}
|
|
1292
1691
|
);
|
|
1293
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
"
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1319
|
-
|
|
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
|
|
1692
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1693
|
+
Box6__default.default,
|
|
1694
|
+
{
|
|
1695
|
+
"data-rdp-ignore": "",
|
|
1696
|
+
sx: {
|
|
1697
|
+
position: "fixed",
|
|
1698
|
+
bottom: 96,
|
|
1699
|
+
right: 24,
|
|
1700
|
+
zIndex: (t) => t.zIndex.modal + 1,
|
|
1701
|
+
width: "min(460px, calc(100vw - 32px))",
|
|
1702
|
+
maxHeight: "min(78vh, 720px)",
|
|
1703
|
+
display: "flex",
|
|
1704
|
+
flexDirection: "column",
|
|
1705
|
+
borderRadius: 2,
|
|
1706
|
+
overflow: "hidden",
|
|
1707
|
+
border: "1px solid",
|
|
1708
|
+
borderColor: "divider",
|
|
1709
|
+
bgcolor: "background.paper",
|
|
1710
|
+
boxShadow: 12
|
|
1711
|
+
},
|
|
1712
|
+
children: [
|
|
1713
|
+
/* @__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: [
|
|
1714
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Stack__default.default, { direction: "row", alignItems: "center", spacing: 1, children: [
|
|
1715
|
+
/* @__PURE__ */ jsxRuntime.jsx(lu.LuWorkflow, { size: 16 }),
|
|
1716
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography3__default.default, { variant: "subtitle2", sx: { fontWeight: 700 }, children: "Component Graph Inspector" }),
|
|
1717
|
+
enabled && /* @__PURE__ */ jsxRuntime.jsx(Chip__default.default, { label: "ON", size: "small", color: "success", variant: "soft", sx: { height: 18, fontSize: "0.6rem", fontWeight: 700 } })
|
|
1718
|
+
] }),
|
|
1719
|
+
/* @__PURE__ */ jsxRuntime.jsx(IconButton__default.default, { size: "small", onClick: onClose, "aria-label": "Close", children: /* @__PURE__ */ jsxRuntime.jsx(lu.LuX, { size: 16 }) })
|
|
1352
1720
|
] }),
|
|
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,
|
|
1721
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Box6__default.default, { sx: { flex: 1, overflowY: "auto", p: 1.5 }, children: [
|
|
1722
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1723
|
+
Box6__default.default,
|
|
1359
1724
|
{
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1725
|
+
sx: {
|
|
1726
|
+
p: 1.25,
|
|
1727
|
+
borderRadius: 1.5,
|
|
1728
|
+
border: "1px solid",
|
|
1729
|
+
borderColor: enabled ? styles.alpha(theme.palette.success.main, 0.5) : "divider",
|
|
1730
|
+
bgcolor: enabled ? styles.alpha(theme.palette.success.main, 0.08) : "background.default"
|
|
1731
|
+
},
|
|
1732
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(Stack__default.default, { direction: "row", alignItems: "center", justifyContent: "space-between", children: [
|
|
1733
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Box6__default.default, { children: [
|
|
1734
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography3__default.default, { variant: "body2", sx: { fontWeight: 700 }, children: "Inspect mode" }),
|
|
1735
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography3__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" })
|
|
1736
|
+
] }),
|
|
1737
|
+
/* @__PURE__ */ jsxRuntime.jsx(Switch__default.default, { checked: enabled, onChange: () => toggleInspector(config.graphEndpoint) })
|
|
1738
|
+
] })
|
|
1368
1739
|
}
|
|
1369
|
-
)
|
|
1370
|
-
selected && !search.trim() && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { marginTop: 12 }, children: details })
|
|
1371
|
-
] }),
|
|
1372
|
-
mode === "page" && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
1740
|
+
),
|
|
1373
1741
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1374
|
-
|
|
1742
|
+
ToggleButtonGroup__default.default,
|
|
1375
1743
|
{
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1744
|
+
fullWidth: true,
|
|
1745
|
+
exclusive: true,
|
|
1746
|
+
size: "small",
|
|
1747
|
+
value: mode,
|
|
1748
|
+
onChange: (_, next) => {
|
|
1749
|
+
if (!next) return;
|
|
1750
|
+
setMode(next);
|
|
1751
|
+
if (next === "graph" || next === "page") void loadGraph(config.graphEndpoint);
|
|
1752
|
+
},
|
|
1753
|
+
sx: { mt: 1.5 },
|
|
1754
|
+
children: TABS.map((t) => /* @__PURE__ */ jsxRuntime.jsxs(ToggleButton__default.default, { value: t.value, sx: { textTransform: "none", gap: 0.5, py: 0.5 }, children: [
|
|
1755
|
+
t.icon,
|
|
1756
|
+
t.label
|
|
1757
|
+
] }, t.value))
|
|
1382
1758
|
}
|
|
1383
1759
|
),
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1760
|
+
/* @__PURE__ */ jsxRuntime.jsx(Divider__default.default, { sx: { my: 1.5 } }),
|
|
1761
|
+
mode === "hover" && /* @__PURE__ */ jsxRuntime.jsxs(Box6__default.default, { children: [
|
|
1762
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography3__default.default, { variant: "caption", sx: { color: "text.disabled", fontWeight: 700, textTransform: "uppercase", letterSpacing: 0.4 }, children: "Last locked component" }),
|
|
1763
|
+
/* @__PURE__ */ jsxRuntime.jsx(Box6__default.default, { sx: { mt: 0.5 }, children: details })
|
|
1764
|
+
] }),
|
|
1765
|
+
mode === "graph" && /* @__PURE__ */ jsxRuntime.jsxs(Box6__default.default, { children: [
|
|
1766
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography3__default.default, { variant: "caption", sx: { display: "block", mb: 0.5, color: status === "ready" ? "success.main" : "text.disabled" }, children: statusText }),
|
|
1767
|
+
(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" } }),
|
|
1768
|
+
/* @__PURE__ */ jsxRuntime.jsx(GraphSearch, { value: search, onChange: setSearch }),
|
|
1769
|
+
/* @__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 }) }),
|
|
1770
|
+
selected && !search.trim() && /* @__PURE__ */ jsxRuntime.jsx(Box6__default.default, { sx: { mt: 1.5 }, children: details })
|
|
1771
|
+
] }),
|
|
1772
|
+
mode === "page" && /* @__PURE__ */ jsxRuntime.jsxs(Box6__default.default, { children: [
|
|
1773
|
+
/* @__PURE__ */ jsxRuntime.jsx(ComponentGraphPageList, { graph, route, selectedName: selected?.componentName, onSelect: selectNode, onOpen: openNode, onCopy: copyNode }),
|
|
1774
|
+
selected && /* @__PURE__ */ jsxRuntime.jsx(Box6__default.default, { sx: { mt: 1.5 }, children: details })
|
|
1775
|
+
] }),
|
|
1776
|
+
mode === "file" && details
|
|
1777
|
+
] })
|
|
1778
|
+
]
|
|
1779
|
+
}
|
|
1780
|
+
);
|
|
1390
1781
|
}
|
|
1782
|
+
var TOOLTIP_W = 360;
|
|
1391
1783
|
function ComponentGraphOverlay() {
|
|
1392
1784
|
const state2 = react.useSyncExternalStore(subscribeGraph, getGraphState, getGraphServerState);
|
|
1785
|
+
const theme = styles.useTheme();
|
|
1393
1786
|
const config = useDevPanelConfig();
|
|
1394
|
-
const [hover, setHover] = react.useState(null);
|
|
1395
1787
|
const route = config.getRoute();
|
|
1396
1788
|
const { enabled } = state2;
|
|
1397
|
-
const
|
|
1398
|
-
|
|
1789
|
+
const [hover, setHover] = react.useState(null);
|
|
1790
|
+
const open = react.useCallback(
|
|
1791
|
+
async (file, line, column) => {
|
|
1399
1792
|
if (!file) {
|
|
1400
|
-
showToast({ message: "No source path \u2014 generate the graph
|
|
1793
|
+
showToast({ message: "No source path \u2014 generate the graph", tone: "error" });
|
|
1401
1794
|
return;
|
|
1402
1795
|
}
|
|
1403
1796
|
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
|
-
);
|
|
1797
|
+
showToast(ok === false ? { message: "Editor unavailable \u2014 path copied", tone: "info" } : { message: "Opening in your editor\u2026", tone: "success" });
|
|
1407
1798
|
},
|
|
1408
1799
|
[config]
|
|
1409
1800
|
);
|
|
@@ -1447,11 +1838,8 @@ function ComponentGraphOverlay() {
|
|
|
1447
1838
|
e.stopPropagation();
|
|
1448
1839
|
setSelected(sel);
|
|
1449
1840
|
setMode("graph");
|
|
1450
|
-
if (e.metaKey || e.ctrlKey)
|
|
1451
|
-
|
|
1452
|
-
} else {
|
|
1453
|
-
showToast({ message: `Locked ${sel.componentName}`, tone: "success" });
|
|
1454
|
-
}
|
|
1841
|
+
if (e.metaKey || e.ctrlKey) void open(sel.absFilePath ?? sel.filePath, sel.line, sel.column);
|
|
1842
|
+
else showToast({ message: `Locked ${sel.componentName}`, tone: "success" });
|
|
1455
1843
|
};
|
|
1456
1844
|
document.addEventListener("pointermove", onMove, { passive: true });
|
|
1457
1845
|
document.addEventListener("keydown", onKey, true);
|
|
@@ -1463,47 +1851,92 @@ function ComponentGraphOverlay() {
|
|
|
1463
1851
|
document.removeEventListener("click", onClick, true);
|
|
1464
1852
|
setHover(null);
|
|
1465
1853
|
};
|
|
1466
|
-
}, [enabled, route,
|
|
1854
|
+
}, [enabled, route, open]);
|
|
1467
1855
|
if (!enabled) return null;
|
|
1468
|
-
const flipX = typeof window !== "undefined" && hover && hover.x +
|
|
1856
|
+
const flipX = typeof window !== "undefined" && hover && hover.x + TOOLTIP_W + 14 > window.innerWidth;
|
|
1469
1857
|
const flipY = typeof window !== "undefined" && hover && hover.y + 140 > window.innerHeight;
|
|
1470
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("
|
|
1858
|
+
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
1859
|
hover && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1472
|
-
|
|
1860
|
+
Box6__default.default,
|
|
1473
1861
|
{
|
|
1474
|
-
|
|
1475
|
-
|
|
1862
|
+
sx: {
|
|
1863
|
+
position: "fixed",
|
|
1864
|
+
top: hover.rect.top,
|
|
1865
|
+
left: hover.rect.left,
|
|
1866
|
+
width: hover.rect.width,
|
|
1867
|
+
height: hover.rect.height,
|
|
1868
|
+
border: "1px solid",
|
|
1869
|
+
borderColor: "primary.main",
|
|
1870
|
+
bgcolor: styles.alpha(theme.palette.primary.main, 0.12),
|
|
1871
|
+
borderRadius: 0.5,
|
|
1872
|
+
boxShadow: `0 0 0 1px ${styles.alpha(theme.palette.primary.main, 0.4)}`,
|
|
1873
|
+
transition: "all 60ms linear"
|
|
1874
|
+
}
|
|
1476
1875
|
}
|
|
1477
1876
|
),
|
|
1478
1877
|
hover && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1479
|
-
|
|
1878
|
+
Box6__default.default,
|
|
1480
1879
|
{
|
|
1481
|
-
|
|
1482
|
-
|
|
1880
|
+
sx: {
|
|
1881
|
+
position: "fixed",
|
|
1483
1882
|
top: flipY ? void 0 : hover.y + 14,
|
|
1484
1883
|
bottom: flipY ? window.innerHeight - hover.y + 14 : void 0,
|
|
1485
1884
|
left: flipX ? void 0 : hover.x + 14,
|
|
1486
|
-
right: flipX ? window.innerWidth - hover.x + 14 : void 0
|
|
1885
|
+
right: flipX ? window.innerWidth - hover.x + 14 : void 0,
|
|
1886
|
+
maxWidth: TOOLTIP_W,
|
|
1887
|
+
px: 1.25,
|
|
1888
|
+
py: 1,
|
|
1889
|
+
borderRadius: 1.5,
|
|
1890
|
+
border: "1px solid",
|
|
1891
|
+
borderColor: styles.alpha(theme.palette.common.white, 0.12),
|
|
1892
|
+
bgcolor: styles.alpha(theme.palette.grey[900], 0.85),
|
|
1893
|
+
backdropFilter: "blur(8px)",
|
|
1894
|
+
boxShadow: "0 8px 28px rgba(0,0,0,0.45)",
|
|
1895
|
+
color: theme.palette.common.white
|
|
1487
1896
|
},
|
|
1488
1897
|
children: [
|
|
1489
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1490
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1491
|
-
|
|
1898
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Stack__default.default, { direction: "row", alignItems: "center", spacing: 0.75, sx: { mb: hover.filePath ? 0.5 : 0 }, children: [
|
|
1899
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1900
|
+
Chip__default.default,
|
|
1901
|
+
{
|
|
1902
|
+
label: hover.name,
|
|
1903
|
+
size: "small",
|
|
1904
|
+
sx: { height: 18, fontWeight: 700, fontSize: "0.65rem", color: "#fff", bgcolor: styles.alpha(theme.palette.primary.main, 0.5) }
|
|
1905
|
+
}
|
|
1906
|
+
),
|
|
1907
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography3__default.default, { variant: "caption", sx: { color: styles.alpha(theme.palette.common.white, 0.6), fontFamily: "monospace" }, children: `<${hover.domTag}>` })
|
|
1492
1908
|
] }),
|
|
1493
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1494
|
-
hover.route && /* @__PURE__ */ jsxRuntime.jsx("
|
|
1495
|
-
/* @__PURE__ */ jsxRuntime.jsx("
|
|
1909
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography3__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" }),
|
|
1910
|
+
hover.route && /* @__PURE__ */ jsxRuntime.jsx(Typography3__default.default, { variant: "caption", sx: { display: "block", fontSize: "0.62rem", color: styles.alpha(theme.palette.common.white, 0.45) }, children: hover.route }),
|
|
1911
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography3__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
1912
|
]
|
|
1497
1913
|
}
|
|
1498
1914
|
),
|
|
1499
1915
|
state2.toast && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1500
|
-
|
|
1916
|
+
Box6__default.default,
|
|
1501
1917
|
{
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1918
|
+
sx: {
|
|
1919
|
+
position: "fixed",
|
|
1920
|
+
bottom: 24,
|
|
1921
|
+
left: "50%",
|
|
1922
|
+
transform: "translateX(-50%)",
|
|
1923
|
+
px: 1.5,
|
|
1924
|
+
py: 0.75,
|
|
1925
|
+
borderRadius: 1.5,
|
|
1926
|
+
border: "1px solid",
|
|
1927
|
+
borderColor: styles.alpha(theme.palette.common.white, 0.12),
|
|
1928
|
+
bgcolor: styles.alpha(theme.palette.grey[900], 0.9),
|
|
1929
|
+
backdropFilter: "blur(8px)",
|
|
1930
|
+
boxShadow: "0 8px 28px rgba(0,0,0,0.45)"
|
|
1505
1931
|
},
|
|
1506
|
-
children:
|
|
1932
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1933
|
+
Typography3__default.default,
|
|
1934
|
+
{
|
|
1935
|
+
variant: "caption",
|
|
1936
|
+
sx: { fontWeight: 600, color: state2.toast.tone === "success" ? "success.light" : state2.toast.tone === "error" ? "error.light" : "common.white" },
|
|
1937
|
+
children: state2.toast.message
|
|
1938
|
+
}
|
|
1939
|
+
)
|
|
1507
1940
|
}
|
|
1508
1941
|
)
|
|
1509
1942
|
] });
|
|
@@ -1513,191 +1946,237 @@ var componentGraphTool = {
|
|
|
1513
1946
|
title: "Component Graph Inspector",
|
|
1514
1947
|
subtitle: "Inspect component tree & open source files",
|
|
1515
1948
|
color: "primary",
|
|
1516
|
-
icon: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1949
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(lu.LuWorkflow, { size: 19 }),
|
|
1517
1950
|
Panel: ComponentGraphPanel,
|
|
1518
1951
|
Overlay: ComponentGraphOverlay
|
|
1519
1952
|
};
|
|
1520
1953
|
function registerComponentGraph() {
|
|
1521
1954
|
registerTool(componentGraphTool);
|
|
1522
1955
|
}
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1956
|
+
function ToolTile({ color, size = 38, children }) {
|
|
1957
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1958
|
+
Box6__default.default,
|
|
1959
|
+
{
|
|
1960
|
+
sx: (theme) => ({
|
|
1961
|
+
width: size,
|
|
1962
|
+
height: size,
|
|
1963
|
+
flexShrink: 0,
|
|
1964
|
+
borderRadius: 1.5,
|
|
1965
|
+
display: "grid",
|
|
1966
|
+
placeItems: "center",
|
|
1967
|
+
color: theme.palette[color].main,
|
|
1968
|
+
bgcolor: styles.alpha(theme.palette[color].main, 0.14)
|
|
1969
|
+
}),
|
|
1970
|
+
children
|
|
1971
|
+
}
|
|
1972
|
+
);
|
|
1973
|
+
}
|
|
1974
|
+
var STORAGE_KEY2 = "react-dev-panel:corner";
|
|
1975
|
+
var EDGE_GAP = 24;
|
|
1976
|
+
var FAB_SIZE = 56;
|
|
1526
1977
|
var DRAG_THRESHOLD = 5;
|
|
1527
1978
|
function isCorner(v) {
|
|
1528
1979
|
return v === "top-left" || v === "top-right" || v === "bottom-left" || v === "bottom-right";
|
|
1529
1980
|
}
|
|
1530
|
-
function
|
|
1981
|
+
function readStoredCorner() {
|
|
1531
1982
|
if (typeof window === "undefined") return "bottom-right";
|
|
1532
1983
|
try {
|
|
1533
|
-
const
|
|
1534
|
-
if (isCorner(
|
|
1984
|
+
const stored = window.localStorage.getItem(STORAGE_KEY2);
|
|
1985
|
+
if (isCorner(stored)) return stored;
|
|
1535
1986
|
} catch {
|
|
1536
1987
|
}
|
|
1537
1988
|
return "bottom-right";
|
|
1538
1989
|
}
|
|
1539
1990
|
function useDraggableCorner() {
|
|
1540
1991
|
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
|
-
|
|
1992
|
+
const [dragPos, setDragPos] = react.useState(null);
|
|
1993
|
+
const movedRef = react.useRef(false);
|
|
1994
|
+
const offsetRef = react.useRef({ x: 0, y: 0 });
|
|
1995
|
+
react.useEffect(() => setCorner(readStoredCorner()), []);
|
|
1996
|
+
const onPointerDown = react.useCallback((event) => {
|
|
1997
|
+
if (event.button !== 0) return;
|
|
1998
|
+
const rect = event.currentTarget.getBoundingClientRect();
|
|
1999
|
+
offsetRef.current = { x: event.clientX - rect.left, y: event.clientY - rect.top };
|
|
2000
|
+
movedRef.current = false;
|
|
2001
|
+
const startX = event.clientX;
|
|
2002
|
+
const startY = event.clientY;
|
|
2003
|
+
const handleMove = (ev) => {
|
|
2004
|
+
if (!movedRef.current && Math.hypot(ev.clientX - startX, ev.clientY - startY) < DRAG_THRESHOLD) return;
|
|
2005
|
+
movedRef.current = true;
|
|
2006
|
+
setDragPos({ x: ev.clientX - offsetRef.current.x, y: ev.clientY - offsetRef.current.y });
|
|
1556
2007
|
};
|
|
1557
|
-
const
|
|
1558
|
-
window.removeEventListener("pointermove",
|
|
1559
|
-
window.removeEventListener("pointerup",
|
|
1560
|
-
if (
|
|
1561
|
-
const
|
|
1562
|
-
const
|
|
1563
|
-
const next = `${
|
|
2008
|
+
const handleUp = (ev) => {
|
|
2009
|
+
window.removeEventListener("pointermove", handleMove);
|
|
2010
|
+
window.removeEventListener("pointerup", handleUp);
|
|
2011
|
+
if (movedRef.current) {
|
|
2012
|
+
const cx = ev.clientX - offsetRef.current.x + FAB_SIZE / 2;
|
|
2013
|
+
const cy = ev.clientY - offsetRef.current.y + FAB_SIZE / 2;
|
|
2014
|
+
const next = `${cy < window.innerHeight / 2 ? "top" : "bottom"}-${cx < window.innerWidth / 2 ? "left" : "right"}`;
|
|
1564
2015
|
setCorner(next);
|
|
1565
2016
|
try {
|
|
1566
|
-
window.localStorage.setItem(
|
|
2017
|
+
window.localStorage.setItem(STORAGE_KEY2, next);
|
|
1567
2018
|
} catch {
|
|
1568
2019
|
}
|
|
1569
2020
|
}
|
|
1570
|
-
|
|
2021
|
+
setDragPos(null);
|
|
1571
2022
|
};
|
|
1572
|
-
window.addEventListener("pointermove",
|
|
1573
|
-
window.addEventListener("pointerup",
|
|
2023
|
+
window.addEventListener("pointermove", handleMove);
|
|
2024
|
+
window.addEventListener("pointerup", handleUp);
|
|
1574
2025
|
}, []);
|
|
1575
|
-
const onClickCapture = react.useCallback((
|
|
1576
|
-
if (
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
2026
|
+
const onClickCapture = react.useCallback((event) => {
|
|
2027
|
+
if (movedRef.current) {
|
|
2028
|
+
event.stopPropagation();
|
|
2029
|
+
event.preventDefault();
|
|
2030
|
+
movedRef.current = false;
|
|
1580
2031
|
}
|
|
1581
2032
|
}, []);
|
|
2033
|
+
const dragging = dragPos !== null;
|
|
1582
2034
|
const isTop = corner.startsWith("top");
|
|
1583
2035
|
const isLeft = corner.endsWith("left");
|
|
1584
|
-
const
|
|
1585
|
-
top: isTop ?
|
|
1586
|
-
bottom: isTop ?
|
|
1587
|
-
left: isLeft ?
|
|
1588
|
-
right: isLeft ?
|
|
2036
|
+
const positionSx = dragging ? { top: dragPos.y, left: dragPos.x, right: "auto", bottom: "auto" } : {
|
|
2037
|
+
top: isTop ? EDGE_GAP : "auto",
|
|
2038
|
+
bottom: isTop ? "auto" : EDGE_GAP,
|
|
2039
|
+
left: isLeft ? EDGE_GAP : "auto",
|
|
2040
|
+
right: isLeft ? "auto" : EDGE_GAP
|
|
1589
2041
|
};
|
|
1590
|
-
return {
|
|
2042
|
+
return { positionSx, onPointerDown, onClickCapture, isTop, isLeft, dragging };
|
|
1591
2043
|
}
|
|
1592
2044
|
function ToolBadge({ tool }) {
|
|
1593
2045
|
const badge = tool.useBadge?.();
|
|
1594
2046
|
if (!badge) return null;
|
|
1595
|
-
const
|
|
1596
|
-
|
|
1597
|
-
|
|
2047
|
+
const color = badge.tone === "error" ? "error" : badge.tone === "success" ? "success" : "default";
|
|
2048
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2049
|
+
Chip__default.default,
|
|
2050
|
+
{
|
|
2051
|
+
size: "small",
|
|
2052
|
+
variant: "soft",
|
|
2053
|
+
color,
|
|
2054
|
+
label: badge.label,
|
|
2055
|
+
sx: { height: 18, fontWeight: 700, fontSize: "0.65rem", "& .MuiChip-label": { px: 0.75 } }
|
|
2056
|
+
}
|
|
2057
|
+
);
|
|
1598
2058
|
}
|
|
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
|
-
};
|
|
2059
|
+
function Launcher({ tools: tools2, onOpenTool }) {
|
|
2060
|
+
const { positionSx, onPointerDown, onClickCapture, isTop, isLeft, dragging } = useDraggableCorner();
|
|
2061
|
+
const [menuAnchor, setMenuAnchor] = react.useState(null);
|
|
1611
2062
|
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1612
2063
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1613
|
-
|
|
2064
|
+
Box6__default.default,
|
|
1614
2065
|
{
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
2066
|
+
"data-rdp-ignore": "",
|
|
2067
|
+
sx: (theme) => ({ position: "fixed", zIndex: theme.zIndex.modal + 2, ...positionSx }),
|
|
2068
|
+
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(
|
|
2069
|
+
Fab__default.default,
|
|
2070
|
+
{
|
|
2071
|
+
onClick: (e) => setMenuAnchor(e.currentTarget),
|
|
2072
|
+
onClickCapture,
|
|
2073
|
+
onPointerDown,
|
|
2074
|
+
"aria-label": "Open Developer Tools",
|
|
2075
|
+
"aria-haspopup": "menu",
|
|
2076
|
+
sx: (theme) => ({
|
|
2077
|
+
width: FAB_SIZE,
|
|
2078
|
+
height: FAB_SIZE,
|
|
2079
|
+
touchAction: "none",
|
|
2080
|
+
cursor: dragging ? "grabbing" : "grab",
|
|
2081
|
+
color: theme.palette.primary.contrastText,
|
|
2082
|
+
background: `linear-gradient(135deg, ${theme.palette.primary.main}, ${theme.palette.primary.dark})`,
|
|
2083
|
+
boxShadow: `0 4px 12px ${styles.alpha(theme.palette.primary.main, 0.24)}, 0 8px 24px rgba(0,0,0,0.5)`,
|
|
2084
|
+
"&:hover": {
|
|
2085
|
+
background: `linear-gradient(135deg, ${theme.palette.primary.dark}, ${theme.palette.primary.dark})`
|
|
2086
|
+
}
|
|
2087
|
+
}),
|
|
2088
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lu.LuWrench, { size: 22 })
|
|
2089
|
+
}
|
|
2090
|
+
) })
|
|
1624
2091
|
}
|
|
1625
2092
|
),
|
|
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
|
-
]
|
|
2093
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2094
|
+
Menu__default.default,
|
|
2095
|
+
{
|
|
2096
|
+
anchorEl: menuAnchor,
|
|
2097
|
+
open: Boolean(menuAnchor),
|
|
2098
|
+
onClose: () => setMenuAnchor(null),
|
|
2099
|
+
sx: (theme) => ({ zIndex: theme.zIndex.modal + 2 }),
|
|
2100
|
+
anchorOrigin: { vertical: isTop ? "bottom" : "top", horizontal: isLeft ? "left" : "right" },
|
|
2101
|
+
transformOrigin: { vertical: isTop ? "top" : "bottom", horizontal: isLeft ? "left" : "right" },
|
|
2102
|
+
slotProps: {
|
|
2103
|
+
paper: {
|
|
2104
|
+
sx: {
|
|
2105
|
+
width: 320,
|
|
2106
|
+
mt: isTop ? 1.5 : 0,
|
|
2107
|
+
mb: isTop ? 0 : 1.5,
|
|
2108
|
+
borderRadius: 2.5,
|
|
2109
|
+
overflow: "hidden",
|
|
2110
|
+
border: "1px solid",
|
|
2111
|
+
borderColor: "divider",
|
|
2112
|
+
boxShadow: 16
|
|
2113
|
+
}
|
|
1671
2114
|
},
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
2115
|
+
list: { sx: { py: 0 } }
|
|
2116
|
+
},
|
|
2117
|
+
children: [
|
|
2118
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2119
|
+
Box6__default.default,
|
|
2120
|
+
{
|
|
2121
|
+
sx: {
|
|
2122
|
+
display: "flex",
|
|
2123
|
+
alignItems: "center",
|
|
2124
|
+
gap: 1.25,
|
|
2125
|
+
px: 2,
|
|
2126
|
+
py: 1.5,
|
|
2127
|
+
background: (theme) => `linear-gradient(135deg, ${styles.alpha(theme.palette.primary.main, 0.16)}, ${styles.alpha(theme.palette.primary.main, 0.04)})`
|
|
2128
|
+
},
|
|
2129
|
+
children: [
|
|
2130
|
+
/* @__PURE__ */ jsxRuntime.jsx(ToolTile, { color: "primary", size: 34, children: /* @__PURE__ */ jsxRuntime.jsx(lu.LuWrench, { size: 17 }) }),
|
|
2131
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Box6__default.default, { sx: { minWidth: 0 }, children: [
|
|
2132
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography3__default.default, { variant: "subtitle2", sx: { fontWeight: 700, lineHeight: 1.2 }, children: "Developer Tools" }),
|
|
2133
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography3__default.default, { variant: "caption", sx: { color: "text.secondary" }, children: "Internal utilities" })
|
|
2134
|
+
] })
|
|
2135
|
+
]
|
|
2136
|
+
}
|
|
2137
|
+
),
|
|
2138
|
+
/* @__PURE__ */ jsxRuntime.jsx(Divider__default.default, {}),
|
|
2139
|
+
/* @__PURE__ */ jsxRuntime.jsx(Box6__default.default, { sx: { p: 1 }, children: tools2.map((tool, i) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2140
|
+
MenuItem__default.default,
|
|
2141
|
+
{
|
|
2142
|
+
onClick: () => {
|
|
2143
|
+
onOpenTool(tool.id);
|
|
2144
|
+
setMenuAnchor(null);
|
|
2145
|
+
},
|
|
2146
|
+
disableGutters: true,
|
|
2147
|
+
sx: { alignItems: "flex-start", gap: 1.25, px: 1.25, py: 1.25, mt: i === 0 ? 0 : 0.5, borderRadius: 1.5, whiteSpace: "normal" },
|
|
2148
|
+
children: [
|
|
2149
|
+
/* @__PURE__ */ jsxRuntime.jsx(ToolTile, { color: tool.color ?? "primary", children: tool.icon }),
|
|
2150
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Box6__default.default, { sx: { flex: 1, minWidth: 0 }, children: [
|
|
2151
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography3__default.default, { variant: "subtitle2", sx: { fontWeight: 600, lineHeight: 1.3 }, children: tool.title }),
|
|
2152
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography3__default.default, { variant: "caption", sx: { color: "text.secondary", display: "block" }, children: tool.subtitle })
|
|
2153
|
+
] }),
|
|
2154
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Stack__default.default, { direction: "row", spacing: 0.5, alignItems: "center", sx: { mt: 0.25 }, children: [
|
|
2155
|
+
/* @__PURE__ */ jsxRuntime.jsx(ToolBadge, { tool }),
|
|
2156
|
+
/* @__PURE__ */ jsxRuntime.jsx(Box6__default.default, { sx: { display: "grid", placeItems: "center", color: "text.disabled" }, children: /* @__PURE__ */ jsxRuntime.jsx(lu.LuChevronRight, { size: 16 }) })
|
|
2157
|
+
] })
|
|
2158
|
+
]
|
|
2159
|
+
},
|
|
2160
|
+
tool.id
|
|
2161
|
+
)) })
|
|
2162
|
+
]
|
|
2163
|
+
}
|
|
2164
|
+
)
|
|
1676
2165
|
] });
|
|
1677
2166
|
}
|
|
1678
2167
|
function DevPanel(config) {
|
|
1679
2168
|
const enabled = config.enabled ?? (typeof process !== "undefined" ? process.env.NODE_ENV !== "production" : true);
|
|
1680
|
-
react.useEffect(() => {
|
|
1681
|
-
if (enabled) injectBaseStyles();
|
|
1682
|
-
}, [enabled]);
|
|
1683
2169
|
if (!enabled) return null;
|
|
1684
|
-
return /* @__PURE__ */ jsxRuntime.jsx(DevPanelConfigProvider, { config, children: /* @__PURE__ */ jsxRuntime.jsx(DevPanelInner, { ids: config.tools
|
|
2170
|
+
return /* @__PURE__ */ jsxRuntime.jsx(DevPanelConfigProvider, { config, children: /* @__PURE__ */ jsxRuntime.jsx(DevPanelInner, { ids: config.tools }) });
|
|
1685
2171
|
}
|
|
1686
|
-
function DevPanelInner({
|
|
1687
|
-
ids,
|
|
1688
|
-
theme
|
|
1689
|
-
}) {
|
|
2172
|
+
function DevPanelInner({ ids }) {
|
|
1690
2173
|
const tools2 = react.useMemo(() => resolveTools(ids), [ids]);
|
|
1691
2174
|
const [openId, setOpenId] = react.useState(null);
|
|
1692
2175
|
react.useEffect(() => {
|
|
1693
2176
|
tools2.forEach((t) => t.init?.());
|
|
1694
2177
|
}, [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
2178
|
const ActivePanel = tools2.find((t) => t.id === openId)?.Panel ?? null;
|
|
1700
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2179
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1701
2180
|
/* @__PURE__ */ jsxRuntime.jsx(Launcher, { tools: tools2, onOpenTool: setOpenId }),
|
|
1702
2181
|
ActivePanel && /* @__PURE__ */ jsxRuntime.jsx(ActivePanel, { onClose: () => setOpenId(null) }),
|
|
1703
2182
|
tools2.map((t) => t.Overlay ? /* @__PURE__ */ jsxRuntime.jsx(t.Overlay, {}, t.id) : null)
|
|
@@ -1737,7 +2216,6 @@ exports.DevPanel = DevPanel;
|
|
|
1737
2216
|
exports.createServerOpenInEditor = createServerOpenInEditor;
|
|
1738
2217
|
exports.defaultOpenInEditor = defaultOpenInEditor;
|
|
1739
2218
|
exports.getRegisteredTools = getRegisteredTools;
|
|
1740
|
-
exports.injectBaseStyles = injectBaseStyles;
|
|
1741
2219
|
exports.registerTool = registerTool;
|
|
1742
2220
|
exports.serverOpenInEditor = serverOpenInEditor;
|
|
1743
2221
|
exports.useDevPanelConfig = useDevPanelConfig;
|