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