react-dev-panel 0.1.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +1299 -821
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -6
- package/dist/index.d.ts +4 -6
- package/dist/index.js +1281 -822
- package/dist/index.js.map +1 -1
- package/package.json +11 -2
package/dist/index.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 Typography3 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, LuFileCode, LuLink, LuClipboardCopy, LuCopy, LuMousePointerClick, LuLayers, LuFile, LuArrowUp, LuRefreshCw, 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(Typography3, { 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
|
+
)
|
|
631
|
+
] });
|
|
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
|
+
Typography3,
|
|
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(Typography3, { variant: "caption", sx: { color: "text.disabled", fontFamily: "monospace" }, children: formatTime(entry.timestamp) }),
|
|
679
|
+
showPath && entry.path && /* @__PURE__ */ jsx(Typography3, { 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)) }) })
|
|
356
687
|
] });
|
|
357
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(Typography3, { 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(Typography3, { 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,195 +825,171 @@ 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(Typography3, { 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(Typography3, { 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(Typography3, { 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(Typography3, { variant: "caption", sx: { color: `${RATING_COLOR[m.rating]}.main`, ml: "auto" }, children: m.rating })
|
|
885
|
+
] }),
|
|
886
|
+
/* @__PURE__ */ jsx(Typography3, { 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
|
}
|
|
927
|
+
var EDITORS = [
|
|
928
|
+
{ key: "vscode", label: "VS Code" },
|
|
929
|
+
{ key: "cursor", label: "Cursor" },
|
|
930
|
+
{ key: "webstorm", label: "WebStorm" }
|
|
931
|
+
];
|
|
534
932
|
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
|
-
)) });
|
|
933
|
+
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
934
|
}
|
|
547
935
|
function Row({ label, children }) {
|
|
548
|
-
return /* @__PURE__ */ jsxs(
|
|
549
|
-
/* @__PURE__ */ jsx(
|
|
550
|
-
/* @__PURE__ */ jsx(
|
|
936
|
+
return /* @__PURE__ */ jsxs(Stack, { direction: "row", spacing: 1, sx: { mt: 0.5 }, children: [
|
|
937
|
+
/* @__PURE__ */ jsx(Typography3, { variant: "caption", sx: { minWidth: 56, color: "text.disabled", fontWeight: 600, flexShrink: 0 }, children: label }),
|
|
938
|
+
/* @__PURE__ */ jsx(Box6, { sx: { minWidth: 0, flex: 1 }, children })
|
|
551
939
|
] });
|
|
552
940
|
}
|
|
553
941
|
function NodeDetails({
|
|
554
942
|
selected,
|
|
943
|
+
editor,
|
|
555
944
|
onOpen,
|
|
945
|
+
onOpenEditor,
|
|
556
946
|
onCopyInfo,
|
|
557
947
|
onCopyPath,
|
|
558
948
|
onSelectName
|
|
559
949
|
}) {
|
|
560
950
|
if (!selected) {
|
|
561
|
-
return /* @__PURE__ */ jsx(
|
|
951
|
+
return /* @__PURE__ */ jsx(Typography3, { 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
952
|
}
|
|
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
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
disabled: !selected.filePath && !selected.absFilePath,
|
|
604
|
-
title: "Copy file path",
|
|
605
|
-
children: /* @__PURE__ */ jsx(IconFileCode, { size: 15 })
|
|
606
|
-
}
|
|
607
|
-
)
|
|
608
|
-
] })
|
|
609
|
-
]
|
|
610
|
-
}
|
|
611
|
-
);
|
|
953
|
+
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: [
|
|
954
|
+
/* @__PURE__ */ jsxs(Stack, { direction: "row", alignItems: "center", spacing: 0.75, children: [
|
|
955
|
+
/* @__PURE__ */ jsx(Chip, { label: selected.componentName, size: "small", color: "primary", variant: "soft", sx: { height: 20, fontSize: "0.68rem", fontWeight: 700 } }),
|
|
956
|
+
selected.domTag && /* @__PURE__ */ jsx(Typography3, { variant: "caption", sx: { color: "text.disabled", fontFamily: "monospace" }, children: `<${selected.domTag}>` })
|
|
957
|
+
] }),
|
|
958
|
+
selected.filePath ? /* @__PURE__ */ jsxs(Typography3, { variant: "caption", sx: { display: "block", mt: 0.75, fontFamily: "monospace", fontSize: "0.68rem", wordBreak: "break-all", color: "text.secondary" }, children: [
|
|
959
|
+
selected.filePath,
|
|
960
|
+
selected.line ? `:${selected.line}` : "",
|
|
961
|
+
selected.line && selected.column ? `:${selected.column}` : ""
|
|
962
|
+
] }) : /* @__PURE__ */ jsx(Typography3, { 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." }),
|
|
963
|
+
selected.route && /* @__PURE__ */ jsx(Row, { label: "Route", children: /* @__PURE__ */ jsx(Typography3, { variant: "caption", sx: { fontFamily: "monospace" }, children: selected.route }) }),
|
|
964
|
+
selected.parent && /* @__PURE__ */ jsx(Row, { label: "Parent", children: /* @__PURE__ */ jsx(Chips, { names: [selected.parent], onSelect: onSelectName }) }),
|
|
965
|
+
selected.children.length > 0 && /* @__PURE__ */ jsx(Row, { label: "Renders", children: /* @__PURE__ */ jsx(Chips, { names: selected.children, onSelect: onSelectName }) }),
|
|
966
|
+
selected.imports.length > 0 && /* @__PURE__ */ jsx(Row, { label: "Imports", children: /* @__PURE__ */ jsx(Chips, { names: selected.imports, onSelect: onSelectName }) }),
|
|
967
|
+
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: [
|
|
968
|
+
/* @__PURE__ */ jsx(Box6, { component: "span", sx: { color: "primary.main" }, children: p.name }),
|
|
969
|
+
"=",
|
|
970
|
+
p.value
|
|
971
|
+
] }, p.name)) }) }),
|
|
972
|
+
/* @__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" }),
|
|
973
|
+
/* @__PURE__ */ jsxs(Stack, { direction: "row", alignItems: "center", spacing: 0.5, useFlexGap: true, sx: { flexWrap: "wrap", mt: 0.75 }, children: [
|
|
974
|
+
/* @__PURE__ */ jsx(Typography3, { variant: "caption", sx: { color: "text.disabled" }, children: "force:" }),
|
|
975
|
+
EDITORS.map((opt) => /* @__PURE__ */ jsx(
|
|
976
|
+
Button,
|
|
977
|
+
{
|
|
978
|
+
size: "small",
|
|
979
|
+
variant: opt.key === editor ? "contained" : "text",
|
|
980
|
+
startIcon: /* @__PURE__ */ jsx(LuLink, { size: 12 }),
|
|
981
|
+
onClick: () => onOpenEditor(opt.key),
|
|
982
|
+
sx: { textTransform: "none", fontSize: "0.66rem", py: 0.1, minWidth: 0 },
|
|
983
|
+
children: opt.label
|
|
984
|
+
},
|
|
985
|
+
opt.key
|
|
986
|
+
))
|
|
987
|
+
] }),
|
|
988
|
+
/* @__PURE__ */ jsxs(Stack, { direction: "row", spacing: 1, sx: { mt: 1 }, children: [
|
|
989
|
+
/* @__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 }) }) }),
|
|
990
|
+
/* @__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 }) }) }) })
|
|
991
|
+
] })
|
|
992
|
+
] });
|
|
612
993
|
}
|
|
613
994
|
|
|
614
995
|
// src/tools/component-graph/graph-utils.ts
|
|
@@ -875,27 +1256,23 @@ function formatForCopy(s) {
|
|
|
875
1256
|
}
|
|
876
1257
|
var MAX_DEPTH = 6;
|
|
877
1258
|
function Label({ children }) {
|
|
878
|
-
return /* @__PURE__ */ jsx("
|
|
1259
|
+
return /* @__PURE__ */ jsx(Typography3, { 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
1260
|
}
|
|
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) => {
|
|
1261
|
+
function RowActions({ node, onOpen, onCopy }) {
|
|
1262
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1263
|
+
/* @__PURE__ */ jsx(Tooltip2, { title: "Open in editor", placement: "top", children: /* @__PURE__ */ jsx(IconButton, { size: "small", sx: { p: 0.25 }, onClick: (e) => {
|
|
887
1264
|
e.stopPropagation();
|
|
888
1265
|
onOpen(node);
|
|
889
|
-
}, children: /* @__PURE__ */ jsx(
|
|
890
|
-
/* @__PURE__ */ jsx(
|
|
1266
|
+
}, children: /* @__PURE__ */ jsx(LuFileCode, { size: 13 }) }) }),
|
|
1267
|
+
/* @__PURE__ */ jsx(Tooltip2, { title: "Copy file path", placement: "top", children: /* @__PURE__ */ jsx(IconButton, { size: "small", sx: { p: 0.25 }, onClick: (e) => {
|
|
891
1268
|
e.stopPropagation();
|
|
892
1269
|
onCopy(node);
|
|
893
|
-
}, children: /* @__PURE__ */ jsx(
|
|
1270
|
+
}, children: /* @__PURE__ */ jsx(LuCopy, { size: 13 }) }) })
|
|
894
1271
|
] });
|
|
895
1272
|
}
|
|
896
1273
|
function RowShell({
|
|
897
1274
|
depth = 0,
|
|
898
|
-
active,
|
|
1275
|
+
active = false,
|
|
899
1276
|
caret,
|
|
900
1277
|
label,
|
|
901
1278
|
isRoute,
|
|
@@ -903,42 +1280,43 @@ function RowShell({
|
|
|
903
1280
|
actions
|
|
904
1281
|
}) {
|
|
905
1282
|
return /* @__PURE__ */ jsxs(
|
|
906
|
-
|
|
1283
|
+
Stack,
|
|
907
1284
|
{
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
1285
|
+
direction: "row",
|
|
1286
|
+
alignItems: "center",
|
|
1287
|
+
spacing: 0.5,
|
|
1288
|
+
sx: (t) => ({
|
|
1289
|
+
pl: 0.5 + depth * 1.5,
|
|
1290
|
+
pr: 0.5,
|
|
1291
|
+
py: 0.25,
|
|
1292
|
+
borderRadius: 1,
|
|
1293
|
+
bgcolor: active ? alpha(t.palette.primary.main, 0.16) : "transparent",
|
|
1294
|
+
"&:hover": { bgcolor: active ? alpha(t.palette.primary.main, 0.2) : "action.hover" },
|
|
1295
|
+
"&:hover .rdp-row-actions": { opacity: 1 }
|
|
1296
|
+
}),
|
|
916
1297
|
children: [
|
|
917
|
-
/* @__PURE__ */ jsx(
|
|
1298
|
+
/* @__PURE__ */ jsx(Box6, { sx: { width: 16, display: "grid", placeItems: "center", color: "text.disabled" }, children: caret }),
|
|
918
1299
|
/* @__PURE__ */ jsx(
|
|
919
|
-
|
|
1300
|
+
Typography3,
|
|
920
1301
|
{
|
|
921
|
-
type: "button",
|
|
922
1302
|
onClick: onLabel,
|
|
923
|
-
|
|
924
|
-
|
|
1303
|
+
variant: "caption",
|
|
1304
|
+
sx: {
|
|
925
1305
|
flex: 1,
|
|
926
1306
|
minWidth: 0,
|
|
927
|
-
textAlign: "left",
|
|
928
|
-
background: "none",
|
|
929
|
-
border: "none",
|
|
930
1307
|
cursor: "pointer",
|
|
931
|
-
fontSize: 12,
|
|
932
1308
|
fontWeight: active ? 700 : 500,
|
|
933
|
-
|
|
934
|
-
|
|
1309
|
+
fontFamily: "monospace",
|
|
1310
|
+
fontSize: "0.72rem",
|
|
935
1311
|
overflow: "hidden",
|
|
936
|
-
textOverflow: "ellipsis"
|
|
1312
|
+
textOverflow: "ellipsis",
|
|
1313
|
+
whiteSpace: "nowrap",
|
|
1314
|
+
color: isRoute ? "info.main" : active ? "primary.main" : "text.primary"
|
|
937
1315
|
},
|
|
938
1316
|
children: label
|
|
939
1317
|
}
|
|
940
1318
|
),
|
|
941
|
-
actions
|
|
1319
|
+
actions && /* @__PURE__ */ jsx(Stack, { direction: "row", spacing: 0.25, className: "rdp-row-actions", sx: { opacity: 0, transition: "opacity 120ms" }, children: actions })
|
|
942
1320
|
]
|
|
943
1321
|
}
|
|
944
1322
|
);
|
|
@@ -950,14 +1328,14 @@ function Branch({ name, depth, trail, p }) {
|
|
|
950
1328
|
const hasKids = kids.length > 0 && depth < MAX_DEPTH && !trail.has(id);
|
|
951
1329
|
const open = p.expanded.has(id);
|
|
952
1330
|
const active = p.selected?.nodeId === id || p.selected?.componentName === name;
|
|
953
|
-
return /* @__PURE__ */ jsxs(
|
|
1331
|
+
return /* @__PURE__ */ jsxs(Box6, { children: [
|
|
954
1332
|
/* @__PURE__ */ jsx(
|
|
955
1333
|
RowShell,
|
|
956
1334
|
{
|
|
957
1335
|
depth,
|
|
958
1336
|
active,
|
|
959
1337
|
isRoute: node?.type === "route",
|
|
960
|
-
caret: hasKids ? /* @__PURE__ */ jsx(
|
|
1338
|
+
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
1339
|
label: name,
|
|
962
1340
|
onLabel: () => node && p.onSelect(node),
|
|
963
1341
|
actions: node ? /* @__PURE__ */ jsx(RowActions, { node, onOpen: p.onOpen, onCopy: p.onCopy }) : null
|
|
@@ -970,7 +1348,7 @@ function ComponentGraphTree(p) {
|
|
|
970
1348
|
const { graph, selected, search } = p;
|
|
971
1349
|
if (graph && search.trim()) {
|
|
972
1350
|
const results = searchNodes(graph, search);
|
|
973
|
-
return /* @__PURE__ */ jsxs(
|
|
1351
|
+
return /* @__PURE__ */ jsxs(Box6, { children: [
|
|
974
1352
|
/* @__PURE__ */ jsxs(Label, { children: [
|
|
975
1353
|
results.length,
|
|
976
1354
|
" match",
|
|
@@ -987,7 +1365,7 @@ function ComponentGraphTree(p) {
|
|
|
987
1365
|
},
|
|
988
1366
|
node.id
|
|
989
1367
|
)),
|
|
990
|
-
results.length === 0 && /* @__PURE__ */ jsxs(
|
|
1368
|
+
results.length === 0 && /* @__PURE__ */ jsxs(Typography3, { variant: "caption", sx: { color: "text.disabled", pl: 1 }, children: [
|
|
991
1369
|
"No components match \u201C",
|
|
992
1370
|
search,
|
|
993
1371
|
"\u201D."
|
|
@@ -995,9 +1373,9 @@ function ComponentGraphTree(p) {
|
|
|
995
1373
|
] });
|
|
996
1374
|
}
|
|
997
1375
|
if (!selected) {
|
|
998
|
-
return /* @__PURE__ */ jsx(
|
|
1376
|
+
return /* @__PURE__ */ jsx(Typography3, { 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
1377
|
}
|
|
1000
|
-
return /* @__PURE__ */ jsxs(
|
|
1378
|
+
return /* @__PURE__ */ jsxs(Box6, { children: [
|
|
1001
1379
|
selected.parents.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1002
1380
|
/* @__PURE__ */ jsx(Label, { children: "Parent chain" }),
|
|
1003
1381
|
selected.parents.map((parent) => {
|
|
@@ -1006,7 +1384,7 @@ function ComponentGraphTree(p) {
|
|
|
1006
1384
|
RowShell,
|
|
1007
1385
|
{
|
|
1008
1386
|
isRoute: node?.type === "route",
|
|
1009
|
-
caret: /* @__PURE__ */ jsx(
|
|
1387
|
+
caret: /* @__PURE__ */ jsx(LuArrowUp, { size: 12 }),
|
|
1010
1388
|
label: parent,
|
|
1011
1389
|
onLabel: () => node && p.onSelect(node),
|
|
1012
1390
|
actions: node ? /* @__PURE__ */ jsx(RowActions, { node, onOpen: p.onOpen, onCopy: p.onCopy }) : null
|
|
@@ -1016,13 +1394,13 @@ function ComponentGraphTree(p) {
|
|
|
1016
1394
|
})
|
|
1017
1395
|
] }),
|
|
1018
1396
|
/* @__PURE__ */ jsx(Label, { children: "Selected" }),
|
|
1019
|
-
/* @__PURE__ */ jsx(RowShell, { active: true, label: selected.componentName, onLabel: () => void 0 }),
|
|
1397
|
+
/* @__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
1398
|
/* @__PURE__ */ jsxs(Label, { children: [
|
|
1021
1399
|
"Renders (",
|
|
1022
1400
|
selected.children.length,
|
|
1023
1401
|
")"
|
|
1024
1402
|
] }),
|
|
1025
|
-
selected.children.length === 0 ? /* @__PURE__ */ jsx(
|
|
1403
|
+
selected.children.length === 0 ? /* @__PURE__ */ jsx(Typography3, { 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
1404
|
selected.imports.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1027
1405
|
/* @__PURE__ */ jsxs(Label, { children: [
|
|
1028
1406
|
"Imports (",
|
|
@@ -1069,56 +1447,60 @@ function ComponentGraphPageList({
|
|
|
1069
1447
|
};
|
|
1070
1448
|
}, [scan, route]);
|
|
1071
1449
|
if (!graph) {
|
|
1072
|
-
return /* @__PURE__ */ jsx(
|
|
1450
|
+
return /* @__PURE__ */ jsx(Typography3, { 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
1451
|
}
|
|
1074
1452
|
const q = query.trim().toLowerCase();
|
|
1075
1453
|
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",
|
|
1454
|
+
return /* @__PURE__ */ jsxs(Box6, { children: [
|
|
1455
|
+
/* @__PURE__ */ jsxs(Stack, { direction: "row", alignItems: "center", justifyContent: "space-between", sx: { mb: 0.5 }, children: [
|
|
1456
|
+
/* @__PURE__ */ jsxs(Typography3, { variant: "caption", sx: { color: "text.secondary" }, children: [
|
|
1457
|
+
/* @__PURE__ */ jsx(Box6, { component: "span", sx: { fontFamily: "monospace", color: "info.main" }, children: route ?? "/" }),
|
|
1081
1458
|
" ",
|
|
1459
|
+
"\xB7 ",
|
|
1082
1460
|
q ? `${filtered.length} / ${items.length}` : items.length,
|
|
1083
1461
|
" component",
|
|
1084
1462
|
items.length === 1 ? "" : "s"
|
|
1085
1463
|
] }),
|
|
1086
|
-
/* @__PURE__ */
|
|
1087
|
-
/* @__PURE__ */ jsx(IconRefresh, { size: 13 }),
|
|
1088
|
-
" Rescan"
|
|
1089
|
-
] })
|
|
1464
|
+
/* @__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
1465
|
] }),
|
|
1091
|
-
/* @__PURE__ */ jsx(
|
|
1092
|
-
items.length === 0 ? /* @__PURE__ */ jsx(
|
|
1466
|
+
/* @__PURE__ */ jsx(Box6, { sx: { mb: 1 }, children: /* @__PURE__ */ jsx(GraphSearch, { value: query, onChange: setQuery, placeholder: "Filter components on this page\u2026" }) }),
|
|
1467
|
+
items.length === 0 ? /* @__PURE__ */ jsx(Typography3, { 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(Typography3, { variant: "caption", sx: { color: "text.disabled", pl: 0.5 }, children: [
|
|
1093
1468
|
"No components match \u201C",
|
|
1094
1469
|
query,
|
|
1095
1470
|
"\u201D."
|
|
1096
1471
|
] }) : filtered.map(({ name, node, count }) => /* @__PURE__ */ jsxs(
|
|
1097
|
-
|
|
1472
|
+
Stack,
|
|
1098
1473
|
{
|
|
1099
|
-
|
|
1100
|
-
|
|
1474
|
+
direction: "row",
|
|
1475
|
+
alignItems: "center",
|
|
1476
|
+
spacing: 0.5,
|
|
1101
1477
|
onClick: () => onSelect(node),
|
|
1478
|
+
sx: (t) => ({
|
|
1479
|
+
px: 0.5,
|
|
1480
|
+
py: 0.4,
|
|
1481
|
+
borderRadius: 1,
|
|
1482
|
+
cursor: "pointer",
|
|
1483
|
+
bgcolor: selectedName === name ? alpha(t.palette.primary.main, 0.16) : "transparent",
|
|
1484
|
+
"&:hover": { bgcolor: "action.hover" },
|
|
1485
|
+
"&:hover .rdp-row-actions": { opacity: 1 }
|
|
1486
|
+
}),
|
|
1102
1487
|
children: [
|
|
1103
|
-
/* @__PURE__ */ jsxs(
|
|
1104
|
-
/* @__PURE__ */ jsxs(
|
|
1105
|
-
/* @__PURE__ */ jsx(
|
|
1106
|
-
count > 1 && /* @__PURE__ */
|
|
1107
|
-
"\xD7",
|
|
1108
|
-
count
|
|
1109
|
-
] })
|
|
1488
|
+
/* @__PURE__ */ jsxs(Box6, { sx: { flex: 1, minWidth: 0 }, children: [
|
|
1489
|
+
/* @__PURE__ */ jsxs(Stack, { direction: "row", alignItems: "center", spacing: 0.5, children: [
|
|
1490
|
+
/* @__PURE__ */ jsx(Typography3, { variant: "caption", sx: { fontFamily: "monospace", fontWeight: 600, fontSize: "0.72rem", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }, children: name }),
|
|
1491
|
+
count > 1 && /* @__PURE__ */ jsx(Chip, { label: `\xD7${count}`, size: "small", variant: "soft", sx: { height: 15, fontSize: "0.55rem", "& .MuiChip-label": { px: 0.5 } } })
|
|
1110
1492
|
] }),
|
|
1111
|
-
/* @__PURE__ */ jsx(
|
|
1493
|
+
/* @__PURE__ */ jsx(Typography3, { variant: "caption", sx: { display: "block", color: "text.disabled", fontSize: "0.62rem", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }, children: node.filePath })
|
|
1112
1494
|
] }),
|
|
1113
|
-
/* @__PURE__ */ jsxs(
|
|
1114
|
-
/* @__PURE__ */ jsx(
|
|
1495
|
+
/* @__PURE__ */ jsxs(Stack, { direction: "row", spacing: 0.25, className: "rdp-row-actions", sx: { opacity: 0, transition: "opacity 120ms" }, children: [
|
|
1496
|
+
/* @__PURE__ */ jsx(Tooltip2, { title: "Open in editor", placement: "top", children: /* @__PURE__ */ jsx(IconButton, { size: "small", sx: { p: 0.25 }, onClick: (e) => {
|
|
1115
1497
|
e.stopPropagation();
|
|
1116
1498
|
onOpen(node);
|
|
1117
|
-
}, children: /* @__PURE__ */ jsx(
|
|
1118
|
-
/* @__PURE__ */ jsx(
|
|
1499
|
+
}, children: /* @__PURE__ */ jsx(LuFileCode, { size: 13 }) }) }),
|
|
1500
|
+
/* @__PURE__ */ jsx(Tooltip2, { title: "Copy file path", placement: "top", children: /* @__PURE__ */ jsx(IconButton, { size: "small", sx: { p: 0.25 }, onClick: (e) => {
|
|
1119
1501
|
e.stopPropagation();
|
|
1120
1502
|
onCopy(node);
|
|
1121
|
-
}, children: /* @__PURE__ */ jsx(
|
|
1503
|
+
}, children: /* @__PURE__ */ jsx(LuCopy, { size: 13 }) }) })
|
|
1122
1504
|
] })
|
|
1123
1505
|
]
|
|
1124
1506
|
},
|
|
@@ -1220,10 +1602,10 @@ function loadGraph(endpoint, force = false) {
|
|
|
1220
1602
|
return graphPromise;
|
|
1221
1603
|
}
|
|
1222
1604
|
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(
|
|
1605
|
+
{ value: "hover", label: "Hover", icon: /* @__PURE__ */ jsx(LuMousePointerClick, { size: 14 }) },
|
|
1606
|
+
{ value: "graph", label: "Graph", icon: /* @__PURE__ */ jsx(LuWorkflow, { size: 14 }) },
|
|
1607
|
+
{ value: "page", label: "Page", icon: /* @__PURE__ */ jsx(LuLayers, { size: 14 }) },
|
|
1608
|
+
{ value: "file", label: "File", icon: /* @__PURE__ */ jsx(LuFile, { size: 14 }) }
|
|
1227
1609
|
];
|
|
1228
1610
|
async function copy(text) {
|
|
1229
1611
|
if (typeof navigator === "undefined" || !navigator.clipboard) return false;
|
|
@@ -1234,17 +1616,15 @@ async function copy(text) {
|
|
|
1234
1616
|
}
|
|
1235
1617
|
function ComponentGraphPanel({ onClose }) {
|
|
1236
1618
|
const state2 = useSyncExternalStore(subscribeGraph, getGraphState, getGraphServerState);
|
|
1619
|
+
const theme = useTheme();
|
|
1237
1620
|
const config = useDevPanelConfig();
|
|
1238
1621
|
const route = config.getRoute();
|
|
1239
1622
|
const { enabled, mode, selected, graph, status, search, expanded } = state2;
|
|
1240
1623
|
const openLoc = useCallback(
|
|
1241
|
-
async (sel) => {
|
|
1624
|
+
async (sel, editor) => {
|
|
1242
1625
|
const file = sel?.absFilePath ?? sel?.filePath;
|
|
1243
|
-
if (!file) {
|
|
1244
|
-
|
|
1245
|
-
return;
|
|
1246
|
-
}
|
|
1247
|
-
const ok = await config.openInEditor?.({ file, line: sel?.line, column: sel?.column }, config.editor);
|
|
1626
|
+
if (!file) return showToast({ message: "No source path available", tone: "error" });
|
|
1627
|
+
const ok = await config.openInEditor?.({ file, line: sel?.line, column: sel?.column }, editor ?? config.editor);
|
|
1248
1628
|
showToast(ok === false ? { message: "Editor unavailable \u2014 path copied", tone: "info" } : { message: "Opening in your editor\u2026", tone: "success" });
|
|
1249
1629
|
},
|
|
1250
1630
|
[config]
|
|
@@ -1253,14 +1633,11 @@ function ComponentGraphPanel({ onClose }) {
|
|
|
1253
1633
|
if (!selected) return;
|
|
1254
1634
|
void copy(formatForCopy(selected)).then((ok) => showToast({ message: ok ? "Component info copied" : "Copy failed", tone: ok ? "success" : "error" }));
|
|
1255
1635
|
}, [selected]);
|
|
1256
|
-
const copyPath = useCallback(
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
},
|
|
1262
|
-
[]
|
|
1263
|
-
);
|
|
1636
|
+
const copyPath = useCallback((sel) => {
|
|
1637
|
+
const path = sel?.filePath ?? sel?.absFilePath;
|
|
1638
|
+
if (!path) return showToast({ message: "No path to copy", tone: "info" });
|
|
1639
|
+
void copy(`${path}${sel?.line ? `:${sel.line}` : ""}`).then((ok) => showToast({ message: ok ? "File path copied" : "Copy failed", tone: ok ? "success" : "error" }));
|
|
1640
|
+
}, []);
|
|
1264
1641
|
const selectName = useCallback(
|
|
1265
1642
|
(name) => {
|
|
1266
1643
|
const node = graph?.nodes.find((n) => n.name === name || n.id === name);
|
|
@@ -1281,126 +1658,120 @@ function ComponentGraphPanel({ onClose }) {
|
|
|
1281
1658
|
NodeDetails,
|
|
1282
1659
|
{
|
|
1283
1660
|
selected,
|
|
1661
|
+
editor: config.editor,
|
|
1284
1662
|
onOpen: () => void openLoc(selected),
|
|
1663
|
+
onOpenEditor: (editor) => void openLoc(selected, editor),
|
|
1285
1664
|
onCopyInfo: copyInfo,
|
|
1286
1665
|
onCopyPath: () => copyPath(selected),
|
|
1287
1666
|
onSelectName: selectName
|
|
1288
1667
|
}
|
|
1289
1668
|
);
|
|
1290
|
-
return /* @__PURE__ */ jsxs(
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
"
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
/* @__PURE__ */ jsx(
|
|
1316
|
-
|
|
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
|
|
1669
|
+
return /* @__PURE__ */ jsxs(
|
|
1670
|
+
Box6,
|
|
1671
|
+
{
|
|
1672
|
+
"data-rdp-ignore": "",
|
|
1673
|
+
sx: {
|
|
1674
|
+
position: "fixed",
|
|
1675
|
+
bottom: 96,
|
|
1676
|
+
right: 24,
|
|
1677
|
+
zIndex: (t) => t.zIndex.modal + 1,
|
|
1678
|
+
width: "min(460px, calc(100vw - 32px))",
|
|
1679
|
+
maxHeight: "min(78vh, 720px)",
|
|
1680
|
+
display: "flex",
|
|
1681
|
+
flexDirection: "column",
|
|
1682
|
+
borderRadius: 2,
|
|
1683
|
+
overflow: "hidden",
|
|
1684
|
+
border: "1px solid",
|
|
1685
|
+
borderColor: "divider",
|
|
1686
|
+
bgcolor: "background.paper",
|
|
1687
|
+
boxShadow: 12
|
|
1688
|
+
},
|
|
1689
|
+
children: [
|
|
1690
|
+
/* @__PURE__ */ jsxs(Stack, { direction: "row", alignItems: "center", justifyContent: "space-between", sx: { px: 1.5, py: 1, borderBottom: "1px solid", borderColor: "divider", flexShrink: 0 }, children: [
|
|
1691
|
+
/* @__PURE__ */ jsxs(Stack, { direction: "row", alignItems: "center", spacing: 1, children: [
|
|
1692
|
+
/* @__PURE__ */ jsx(LuWorkflow, { size: 16 }),
|
|
1693
|
+
/* @__PURE__ */ jsx(Typography3, { variant: "subtitle2", sx: { fontWeight: 700 }, children: "Component Graph Inspector" }),
|
|
1694
|
+
enabled && /* @__PURE__ */ jsx(Chip, { label: "ON", size: "small", color: "success", variant: "soft", sx: { height: 18, fontSize: "0.6rem", fontWeight: 700 } })
|
|
1695
|
+
] }),
|
|
1696
|
+
/* @__PURE__ */ jsx(IconButton, { size: "small", onClick: onClose, "aria-label": "Close", children: /* @__PURE__ */ jsx(LuX, { size: 16 }) })
|
|
1349
1697
|
] }),
|
|
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,
|
|
1698
|
+
/* @__PURE__ */ jsxs(Box6, { sx: { flex: 1, overflowY: "auto", p: 1.5 }, children: [
|
|
1699
|
+
/* @__PURE__ */ jsx(
|
|
1700
|
+
Box6,
|
|
1356
1701
|
{
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1702
|
+
sx: {
|
|
1703
|
+
p: 1.25,
|
|
1704
|
+
borderRadius: 1.5,
|
|
1705
|
+
border: "1px solid",
|
|
1706
|
+
borderColor: enabled ? alpha(theme.palette.success.main, 0.5) : "divider",
|
|
1707
|
+
bgcolor: enabled ? alpha(theme.palette.success.main, 0.08) : "background.default"
|
|
1708
|
+
},
|
|
1709
|
+
children: /* @__PURE__ */ jsxs(Stack, { direction: "row", alignItems: "center", justifyContent: "space-between", children: [
|
|
1710
|
+
/* @__PURE__ */ jsxs(Box6, { children: [
|
|
1711
|
+
/* @__PURE__ */ jsx(Typography3, { variant: "body2", sx: { fontWeight: 700 }, children: "Inspect mode" }),
|
|
1712
|
+
/* @__PURE__ */ jsx(Typography3, { variant: "caption", sx: { color: "text.secondary" }, children: enabled ? "Hover the UI, click to lock \xB7 Esc to exit" : "Enable, then hover the UI" })
|
|
1713
|
+
] }),
|
|
1714
|
+
/* @__PURE__ */ jsx(Switch, { checked: enabled, onChange: () => toggleInspector(config.graphEndpoint) })
|
|
1715
|
+
] })
|
|
1365
1716
|
}
|
|
1366
|
-
)
|
|
1367
|
-
selected && !search.trim() && /* @__PURE__ */ jsx("div", { style: { marginTop: 12 }, children: details })
|
|
1368
|
-
] }),
|
|
1369
|
-
mode === "page" && /* @__PURE__ */ jsxs("div", { children: [
|
|
1717
|
+
),
|
|
1370
1718
|
/* @__PURE__ */ jsx(
|
|
1371
|
-
|
|
1719
|
+
ToggleButtonGroup,
|
|
1372
1720
|
{
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1721
|
+
fullWidth: true,
|
|
1722
|
+
exclusive: true,
|
|
1723
|
+
size: "small",
|
|
1724
|
+
value: mode,
|
|
1725
|
+
onChange: (_, next) => {
|
|
1726
|
+
if (!next) return;
|
|
1727
|
+
setMode(next);
|
|
1728
|
+
if (next === "graph" || next === "page") void loadGraph(config.graphEndpoint);
|
|
1729
|
+
},
|
|
1730
|
+
sx: { mt: 1.5 },
|
|
1731
|
+
children: TABS.map((t) => /* @__PURE__ */ jsxs(ToggleButton, { value: t.value, sx: { textTransform: "none", gap: 0.5, py: 0.5 }, children: [
|
|
1732
|
+
t.icon,
|
|
1733
|
+
t.label
|
|
1734
|
+
] }, t.value))
|
|
1379
1735
|
}
|
|
1380
1736
|
),
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1737
|
+
/* @__PURE__ */ jsx(Divider, { sx: { my: 1.5 } }),
|
|
1738
|
+
mode === "hover" && /* @__PURE__ */ jsxs(Box6, { children: [
|
|
1739
|
+
/* @__PURE__ */ jsx(Typography3, { variant: "caption", sx: { color: "text.disabled", fontWeight: 700, textTransform: "uppercase", letterSpacing: 0.4 }, children: "Last locked component" }),
|
|
1740
|
+
/* @__PURE__ */ jsx(Box6, { sx: { mt: 0.5 }, children: details })
|
|
1741
|
+
] }),
|
|
1742
|
+
mode === "graph" && /* @__PURE__ */ jsxs(Box6, { children: [
|
|
1743
|
+
/* @__PURE__ */ jsx(Typography3, { variant: "caption", sx: { display: "block", mb: 0.5, color: status === "ready" ? "success.main" : "text.disabled" }, children: statusText }),
|
|
1744
|
+
(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" } }),
|
|
1745
|
+
/* @__PURE__ */ jsx(GraphSearch, { value: search, onChange: setSearch }),
|
|
1746
|
+
/* @__PURE__ */ jsx(Box6, { sx: { mt: 1 }, children: /* @__PURE__ */ jsx(ComponentGraphTree, { graph, selected, search, expanded, onSelect: selectNode, onToggle: toggleExpanded, onOpen: openNode, onCopy: copyNode }) }),
|
|
1747
|
+
selected && !search.trim() && /* @__PURE__ */ jsx(Box6, { sx: { mt: 1.5 }, children: details })
|
|
1748
|
+
] }),
|
|
1749
|
+
mode === "page" && /* @__PURE__ */ jsxs(Box6, { children: [
|
|
1750
|
+
/* @__PURE__ */ jsx(ComponentGraphPageList, { graph, route, selectedName: selected?.componentName, onSelect: selectNode, onOpen: openNode, onCopy: copyNode }),
|
|
1751
|
+
selected && /* @__PURE__ */ jsx(Box6, { sx: { mt: 1.5 }, children: details })
|
|
1752
|
+
] }),
|
|
1753
|
+
mode === "file" && details
|
|
1754
|
+
] })
|
|
1755
|
+
]
|
|
1756
|
+
}
|
|
1757
|
+
);
|
|
1387
1758
|
}
|
|
1759
|
+
var TOOLTIP_W = 360;
|
|
1388
1760
|
function ComponentGraphOverlay() {
|
|
1389
1761
|
const state2 = useSyncExternalStore(subscribeGraph, getGraphState, getGraphServerState);
|
|
1762
|
+
const theme = useTheme();
|
|
1390
1763
|
const config = useDevPanelConfig();
|
|
1391
|
-
const [hover, setHover] = useState(null);
|
|
1392
1764
|
const route = config.getRoute();
|
|
1393
1765
|
const { enabled } = state2;
|
|
1394
|
-
const
|
|
1395
|
-
|
|
1766
|
+
const [hover, setHover] = useState(null);
|
|
1767
|
+
const open = useCallback(
|
|
1768
|
+
async (file, line, column) => {
|
|
1396
1769
|
if (!file) {
|
|
1397
|
-
showToast({ message: "No source path \u2014 generate the graph
|
|
1770
|
+
showToast({ message: "No source path \u2014 generate the graph", tone: "error" });
|
|
1398
1771
|
return;
|
|
1399
1772
|
}
|
|
1400
1773
|
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
|
-
);
|
|
1774
|
+
showToast(ok === false ? { message: "Editor unavailable \u2014 path copied", tone: "info" } : { message: "Opening in your editor\u2026", tone: "success" });
|
|
1404
1775
|
},
|
|
1405
1776
|
[config]
|
|
1406
1777
|
);
|
|
@@ -1444,11 +1815,8 @@ function ComponentGraphOverlay() {
|
|
|
1444
1815
|
e.stopPropagation();
|
|
1445
1816
|
setSelected(sel);
|
|
1446
1817
|
setMode("graph");
|
|
1447
|
-
if (e.metaKey || e.ctrlKey)
|
|
1448
|
-
|
|
1449
|
-
} else {
|
|
1450
|
-
showToast({ message: `Locked ${sel.componentName}`, tone: "success" });
|
|
1451
|
-
}
|
|
1818
|
+
if (e.metaKey || e.ctrlKey) void open(sel.absFilePath ?? sel.filePath, sel.line, sel.column);
|
|
1819
|
+
else showToast({ message: `Locked ${sel.componentName}`, tone: "success" });
|
|
1452
1820
|
};
|
|
1453
1821
|
document.addEventListener("pointermove", onMove, { passive: true });
|
|
1454
1822
|
document.addEventListener("keydown", onKey, true);
|
|
@@ -1460,47 +1828,92 @@ function ComponentGraphOverlay() {
|
|
|
1460
1828
|
document.removeEventListener("click", onClick, true);
|
|
1461
1829
|
setHover(null);
|
|
1462
1830
|
};
|
|
1463
|
-
}, [enabled, route,
|
|
1831
|
+
}, [enabled, route, open]);
|
|
1464
1832
|
if (!enabled) return null;
|
|
1465
|
-
const flipX = typeof window !== "undefined" && hover && hover.x +
|
|
1833
|
+
const flipX = typeof window !== "undefined" && hover && hover.x + TOOLTIP_W + 14 > window.innerWidth;
|
|
1466
1834
|
const flipY = typeof window !== "undefined" && hover && hover.y + 140 > window.innerHeight;
|
|
1467
|
-
return /* @__PURE__ */ jsxs("
|
|
1835
|
+
return /* @__PURE__ */ jsxs(Box6, { "data-rdp-ignore": "", sx: { position: "fixed", inset: 0, pointerEvents: "none", zIndex: (t) => t.zIndex.tooltip + 1 }, children: [
|
|
1468
1836
|
hover && /* @__PURE__ */ jsx(
|
|
1469
|
-
|
|
1837
|
+
Box6,
|
|
1470
1838
|
{
|
|
1471
|
-
|
|
1472
|
-
|
|
1839
|
+
sx: {
|
|
1840
|
+
position: "fixed",
|
|
1841
|
+
top: hover.rect.top,
|
|
1842
|
+
left: hover.rect.left,
|
|
1843
|
+
width: hover.rect.width,
|
|
1844
|
+
height: hover.rect.height,
|
|
1845
|
+
border: "1px solid",
|
|
1846
|
+
borderColor: "primary.main",
|
|
1847
|
+
bgcolor: alpha(theme.palette.primary.main, 0.12),
|
|
1848
|
+
borderRadius: 0.5,
|
|
1849
|
+
boxShadow: `0 0 0 1px ${alpha(theme.palette.primary.main, 0.4)}`,
|
|
1850
|
+
transition: "all 60ms linear"
|
|
1851
|
+
}
|
|
1473
1852
|
}
|
|
1474
1853
|
),
|
|
1475
1854
|
hover && /* @__PURE__ */ jsxs(
|
|
1476
|
-
|
|
1855
|
+
Box6,
|
|
1477
1856
|
{
|
|
1478
|
-
|
|
1479
|
-
|
|
1857
|
+
sx: {
|
|
1858
|
+
position: "fixed",
|
|
1480
1859
|
top: flipY ? void 0 : hover.y + 14,
|
|
1481
1860
|
bottom: flipY ? window.innerHeight - hover.y + 14 : void 0,
|
|
1482
1861
|
left: flipX ? void 0 : hover.x + 14,
|
|
1483
|
-
right: flipX ? window.innerWidth - hover.x + 14 : void 0
|
|
1862
|
+
right: flipX ? window.innerWidth - hover.x + 14 : void 0,
|
|
1863
|
+
maxWidth: TOOLTIP_W,
|
|
1864
|
+
px: 1.25,
|
|
1865
|
+
py: 1,
|
|
1866
|
+
borderRadius: 1.5,
|
|
1867
|
+
border: "1px solid",
|
|
1868
|
+
borderColor: alpha(theme.palette.common.white, 0.12),
|
|
1869
|
+
bgcolor: alpha(theme.palette.grey[900], 0.85),
|
|
1870
|
+
backdropFilter: "blur(8px)",
|
|
1871
|
+
boxShadow: "0 8px 28px rgba(0,0,0,0.45)",
|
|
1872
|
+
color: theme.palette.common.white
|
|
1484
1873
|
},
|
|
1485
1874
|
children: [
|
|
1486
|
-
/* @__PURE__ */ jsxs(
|
|
1487
|
-
/* @__PURE__ */ jsx(
|
|
1488
|
-
|
|
1875
|
+
/* @__PURE__ */ jsxs(Stack, { direction: "row", alignItems: "center", spacing: 0.75, sx: { mb: hover.filePath ? 0.5 : 0 }, children: [
|
|
1876
|
+
/* @__PURE__ */ jsx(
|
|
1877
|
+
Chip,
|
|
1878
|
+
{
|
|
1879
|
+
label: hover.name,
|
|
1880
|
+
size: "small",
|
|
1881
|
+
sx: { height: 18, fontWeight: 700, fontSize: "0.65rem", color: "#fff", bgcolor: alpha(theme.palette.primary.main, 0.5) }
|
|
1882
|
+
}
|
|
1883
|
+
),
|
|
1884
|
+
/* @__PURE__ */ jsx(Typography3, { variant: "caption", sx: { color: alpha(theme.palette.common.white, 0.6), fontFamily: "monospace" }, children: `<${hover.domTag}>` })
|
|
1489
1885
|
] }),
|
|
1490
|
-
/* @__PURE__ */ jsx(
|
|
1491
|
-
hover.route && /* @__PURE__ */ jsx("
|
|
1492
|
-
/* @__PURE__ */ jsx("
|
|
1886
|
+
/* @__PURE__ */ jsx(Typography3, { 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" }),
|
|
1887
|
+
hover.route && /* @__PURE__ */ jsx(Typography3, { variant: "caption", sx: { display: "block", fontSize: "0.62rem", color: alpha(theme.palette.common.white, 0.45) }, children: hover.route }),
|
|
1888
|
+
/* @__PURE__ */ jsx(Typography3, { 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
1889
|
]
|
|
1494
1890
|
}
|
|
1495
1891
|
),
|
|
1496
1892
|
state2.toast && /* @__PURE__ */ jsx(
|
|
1497
|
-
|
|
1893
|
+
Box6,
|
|
1498
1894
|
{
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1895
|
+
sx: {
|
|
1896
|
+
position: "fixed",
|
|
1897
|
+
bottom: 24,
|
|
1898
|
+
left: "50%",
|
|
1899
|
+
transform: "translateX(-50%)",
|
|
1900
|
+
px: 1.5,
|
|
1901
|
+
py: 0.75,
|
|
1902
|
+
borderRadius: 1.5,
|
|
1903
|
+
border: "1px solid",
|
|
1904
|
+
borderColor: alpha(theme.palette.common.white, 0.12),
|
|
1905
|
+
bgcolor: alpha(theme.palette.grey[900], 0.9),
|
|
1906
|
+
backdropFilter: "blur(8px)",
|
|
1907
|
+
boxShadow: "0 8px 28px rgba(0,0,0,0.45)"
|
|
1502
1908
|
},
|
|
1503
|
-
children:
|
|
1909
|
+
children: /* @__PURE__ */ jsx(
|
|
1910
|
+
Typography3,
|
|
1911
|
+
{
|
|
1912
|
+
variant: "caption",
|
|
1913
|
+
sx: { fontWeight: 600, color: state2.toast.tone === "success" ? "success.light" : state2.toast.tone === "error" ? "error.light" : "common.white" },
|
|
1914
|
+
children: state2.toast.message
|
|
1915
|
+
}
|
|
1916
|
+
)
|
|
1504
1917
|
}
|
|
1505
1918
|
)
|
|
1506
1919
|
] });
|
|
@@ -1510,191 +1923,237 @@ var componentGraphTool = {
|
|
|
1510
1923
|
title: "Component Graph Inspector",
|
|
1511
1924
|
subtitle: "Inspect component tree & open source files",
|
|
1512
1925
|
color: "primary",
|
|
1513
|
-
icon: /* @__PURE__ */ jsx(
|
|
1926
|
+
icon: /* @__PURE__ */ jsx(LuWorkflow, { size: 19 }),
|
|
1514
1927
|
Panel: ComponentGraphPanel,
|
|
1515
1928
|
Overlay: ComponentGraphOverlay
|
|
1516
1929
|
};
|
|
1517
1930
|
function registerComponentGraph() {
|
|
1518
1931
|
registerTool(componentGraphTool);
|
|
1519
1932
|
}
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1933
|
+
function ToolTile({ color, size = 38, children }) {
|
|
1934
|
+
return /* @__PURE__ */ jsx(
|
|
1935
|
+
Box6,
|
|
1936
|
+
{
|
|
1937
|
+
sx: (theme) => ({
|
|
1938
|
+
width: size,
|
|
1939
|
+
height: size,
|
|
1940
|
+
flexShrink: 0,
|
|
1941
|
+
borderRadius: 1.5,
|
|
1942
|
+
display: "grid",
|
|
1943
|
+
placeItems: "center",
|
|
1944
|
+
color: theme.palette[color].main,
|
|
1945
|
+
bgcolor: alpha(theme.palette[color].main, 0.14)
|
|
1946
|
+
}),
|
|
1947
|
+
children
|
|
1948
|
+
}
|
|
1949
|
+
);
|
|
1950
|
+
}
|
|
1951
|
+
var STORAGE_KEY2 = "react-dev-panel:corner";
|
|
1952
|
+
var EDGE_GAP = 24;
|
|
1953
|
+
var FAB_SIZE = 56;
|
|
1523
1954
|
var DRAG_THRESHOLD = 5;
|
|
1524
1955
|
function isCorner(v) {
|
|
1525
1956
|
return v === "top-left" || v === "top-right" || v === "bottom-left" || v === "bottom-right";
|
|
1526
1957
|
}
|
|
1527
|
-
function
|
|
1958
|
+
function readStoredCorner() {
|
|
1528
1959
|
if (typeof window === "undefined") return "bottom-right";
|
|
1529
1960
|
try {
|
|
1530
|
-
const
|
|
1531
|
-
if (isCorner(
|
|
1961
|
+
const stored = window.localStorage.getItem(STORAGE_KEY2);
|
|
1962
|
+
if (isCorner(stored)) return stored;
|
|
1532
1963
|
} catch {
|
|
1533
1964
|
}
|
|
1534
1965
|
return "bottom-right";
|
|
1535
1966
|
}
|
|
1536
1967
|
function useDraggableCorner() {
|
|
1537
1968
|
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
|
-
|
|
1969
|
+
const [dragPos, setDragPos] = useState(null);
|
|
1970
|
+
const movedRef = useRef(false);
|
|
1971
|
+
const offsetRef = useRef({ x: 0, y: 0 });
|
|
1972
|
+
useEffect(() => setCorner(readStoredCorner()), []);
|
|
1973
|
+
const onPointerDown = useCallback((event) => {
|
|
1974
|
+
if (event.button !== 0) return;
|
|
1975
|
+
const rect = event.currentTarget.getBoundingClientRect();
|
|
1976
|
+
offsetRef.current = { x: event.clientX - rect.left, y: event.clientY - rect.top };
|
|
1977
|
+
movedRef.current = false;
|
|
1978
|
+
const startX = event.clientX;
|
|
1979
|
+
const startY = event.clientY;
|
|
1980
|
+
const handleMove = (ev) => {
|
|
1981
|
+
if (!movedRef.current && Math.hypot(ev.clientX - startX, ev.clientY - startY) < DRAG_THRESHOLD) return;
|
|
1982
|
+
movedRef.current = true;
|
|
1983
|
+
setDragPos({ x: ev.clientX - offsetRef.current.x, y: ev.clientY - offsetRef.current.y });
|
|
1553
1984
|
};
|
|
1554
|
-
const
|
|
1555
|
-
window.removeEventListener("pointermove",
|
|
1556
|
-
window.removeEventListener("pointerup",
|
|
1557
|
-
if (
|
|
1558
|
-
const
|
|
1559
|
-
const
|
|
1560
|
-
const next = `${
|
|
1985
|
+
const handleUp = (ev) => {
|
|
1986
|
+
window.removeEventListener("pointermove", handleMove);
|
|
1987
|
+
window.removeEventListener("pointerup", handleUp);
|
|
1988
|
+
if (movedRef.current) {
|
|
1989
|
+
const cx = ev.clientX - offsetRef.current.x + FAB_SIZE / 2;
|
|
1990
|
+
const cy = ev.clientY - offsetRef.current.y + FAB_SIZE / 2;
|
|
1991
|
+
const next = `${cy < window.innerHeight / 2 ? "top" : "bottom"}-${cx < window.innerWidth / 2 ? "left" : "right"}`;
|
|
1561
1992
|
setCorner(next);
|
|
1562
1993
|
try {
|
|
1563
|
-
window.localStorage.setItem(
|
|
1994
|
+
window.localStorage.setItem(STORAGE_KEY2, next);
|
|
1564
1995
|
} catch {
|
|
1565
1996
|
}
|
|
1566
1997
|
}
|
|
1567
|
-
|
|
1998
|
+
setDragPos(null);
|
|
1568
1999
|
};
|
|
1569
|
-
window.addEventListener("pointermove",
|
|
1570
|
-
window.addEventListener("pointerup",
|
|
2000
|
+
window.addEventListener("pointermove", handleMove);
|
|
2001
|
+
window.addEventListener("pointerup", handleUp);
|
|
1571
2002
|
}, []);
|
|
1572
|
-
const onClickCapture = useCallback((
|
|
1573
|
-
if (
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
2003
|
+
const onClickCapture = useCallback((event) => {
|
|
2004
|
+
if (movedRef.current) {
|
|
2005
|
+
event.stopPropagation();
|
|
2006
|
+
event.preventDefault();
|
|
2007
|
+
movedRef.current = false;
|
|
1577
2008
|
}
|
|
1578
2009
|
}, []);
|
|
2010
|
+
const dragging = dragPos !== null;
|
|
1579
2011
|
const isTop = corner.startsWith("top");
|
|
1580
2012
|
const isLeft = corner.endsWith("left");
|
|
1581
|
-
const
|
|
1582
|
-
top: isTop ?
|
|
1583
|
-
bottom: isTop ?
|
|
1584
|
-
left: isLeft ?
|
|
1585
|
-
right: isLeft ?
|
|
2013
|
+
const positionSx = dragging ? { top: dragPos.y, left: dragPos.x, right: "auto", bottom: "auto" } : {
|
|
2014
|
+
top: isTop ? EDGE_GAP : "auto",
|
|
2015
|
+
bottom: isTop ? "auto" : EDGE_GAP,
|
|
2016
|
+
left: isLeft ? EDGE_GAP : "auto",
|
|
2017
|
+
right: isLeft ? "auto" : EDGE_GAP
|
|
1586
2018
|
};
|
|
1587
|
-
return {
|
|
2019
|
+
return { positionSx, onPointerDown, onClickCapture, isTop, isLeft, dragging };
|
|
1588
2020
|
}
|
|
1589
2021
|
function ToolBadge({ tool }) {
|
|
1590
2022
|
const badge = tool.useBadge?.();
|
|
1591
2023
|
if (!badge) return null;
|
|
1592
|
-
const
|
|
1593
|
-
|
|
1594
|
-
|
|
2024
|
+
const color = badge.tone === "error" ? "error" : badge.tone === "success" ? "success" : "default";
|
|
2025
|
+
return /* @__PURE__ */ jsx(
|
|
2026
|
+
Chip,
|
|
2027
|
+
{
|
|
2028
|
+
size: "small",
|
|
2029
|
+
variant: "soft",
|
|
2030
|
+
color,
|
|
2031
|
+
label: badge.label,
|
|
2032
|
+
sx: { height: 18, fontWeight: 700, fontSize: "0.65rem", "& .MuiChip-label": { px: 0.75 } }
|
|
2033
|
+
}
|
|
2034
|
+
);
|
|
1595
2035
|
}
|
|
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
|
-
};
|
|
2036
|
+
function Launcher({ tools: tools2, onOpenTool }) {
|
|
2037
|
+
const { positionSx, onPointerDown, onClickCapture, isTop, isLeft, dragging } = useDraggableCorner();
|
|
2038
|
+
const [menuAnchor, setMenuAnchor] = useState(null);
|
|
1608
2039
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1609
2040
|
/* @__PURE__ */ jsx(
|
|
1610
|
-
|
|
2041
|
+
Box6,
|
|
1611
2042
|
{
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
2043
|
+
"data-rdp-ignore": "",
|
|
2044
|
+
sx: (theme) => ({ position: "fixed", zIndex: theme.zIndex.modal + 2, ...positionSx }),
|
|
2045
|
+
children: /* @__PURE__ */ jsx(Tooltip2, { title: dragging ? "" : "Developer Tools \u2014 drag to a corner", placement: isLeft ? "right" : "left", arrow: true, children: /* @__PURE__ */ jsx(
|
|
2046
|
+
Fab,
|
|
2047
|
+
{
|
|
2048
|
+
onClick: (e) => setMenuAnchor(e.currentTarget),
|
|
2049
|
+
onClickCapture,
|
|
2050
|
+
onPointerDown,
|
|
2051
|
+
"aria-label": "Open Developer Tools",
|
|
2052
|
+
"aria-haspopup": "menu",
|
|
2053
|
+
sx: (theme) => ({
|
|
2054
|
+
width: FAB_SIZE,
|
|
2055
|
+
height: FAB_SIZE,
|
|
2056
|
+
touchAction: "none",
|
|
2057
|
+
cursor: dragging ? "grabbing" : "grab",
|
|
2058
|
+
color: theme.palette.primary.contrastText,
|
|
2059
|
+
background: `linear-gradient(135deg, ${theme.palette.primary.main}, ${theme.palette.primary.dark})`,
|
|
2060
|
+
boxShadow: `0 4px 12px ${alpha(theme.palette.primary.main, 0.24)}, 0 8px 24px rgba(0,0,0,0.5)`,
|
|
2061
|
+
"&:hover": {
|
|
2062
|
+
background: `linear-gradient(135deg, ${theme.palette.primary.dark}, ${theme.palette.primary.dark})`
|
|
2063
|
+
}
|
|
2064
|
+
}),
|
|
2065
|
+
children: /* @__PURE__ */ jsx(LuWrench, { size: 22 })
|
|
2066
|
+
}
|
|
2067
|
+
) })
|
|
1621
2068
|
}
|
|
1622
2069
|
),
|
|
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
|
-
]
|
|
2070
|
+
/* @__PURE__ */ jsxs(
|
|
2071
|
+
Menu,
|
|
2072
|
+
{
|
|
2073
|
+
anchorEl: menuAnchor,
|
|
2074
|
+
open: Boolean(menuAnchor),
|
|
2075
|
+
onClose: () => setMenuAnchor(null),
|
|
2076
|
+
sx: (theme) => ({ zIndex: theme.zIndex.modal + 2 }),
|
|
2077
|
+
anchorOrigin: { vertical: isTop ? "bottom" : "top", horizontal: isLeft ? "left" : "right" },
|
|
2078
|
+
transformOrigin: { vertical: isTop ? "top" : "bottom", horizontal: isLeft ? "left" : "right" },
|
|
2079
|
+
slotProps: {
|
|
2080
|
+
paper: {
|
|
2081
|
+
sx: {
|
|
2082
|
+
width: 320,
|
|
2083
|
+
mt: isTop ? 1.5 : 0,
|
|
2084
|
+
mb: isTop ? 0 : 1.5,
|
|
2085
|
+
borderRadius: 2.5,
|
|
2086
|
+
overflow: "hidden",
|
|
2087
|
+
border: "1px solid",
|
|
2088
|
+
borderColor: "divider",
|
|
2089
|
+
boxShadow: 16
|
|
2090
|
+
}
|
|
1668
2091
|
},
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
2092
|
+
list: { sx: { py: 0 } }
|
|
2093
|
+
},
|
|
2094
|
+
children: [
|
|
2095
|
+
/* @__PURE__ */ jsxs(
|
|
2096
|
+
Box6,
|
|
2097
|
+
{
|
|
2098
|
+
sx: {
|
|
2099
|
+
display: "flex",
|
|
2100
|
+
alignItems: "center",
|
|
2101
|
+
gap: 1.25,
|
|
2102
|
+
px: 2,
|
|
2103
|
+
py: 1.5,
|
|
2104
|
+
background: (theme) => `linear-gradient(135deg, ${alpha(theme.palette.primary.main, 0.16)}, ${alpha(theme.palette.primary.main, 0.04)})`
|
|
2105
|
+
},
|
|
2106
|
+
children: [
|
|
2107
|
+
/* @__PURE__ */ jsx(ToolTile, { color: "primary", size: 34, children: /* @__PURE__ */ jsx(LuWrench, { size: 17 }) }),
|
|
2108
|
+
/* @__PURE__ */ jsxs(Box6, { sx: { minWidth: 0 }, children: [
|
|
2109
|
+
/* @__PURE__ */ jsx(Typography3, { variant: "subtitle2", sx: { fontWeight: 700, lineHeight: 1.2 }, children: "Developer Tools" }),
|
|
2110
|
+
/* @__PURE__ */ jsx(Typography3, { variant: "caption", sx: { color: "text.secondary" }, children: "Internal utilities" })
|
|
2111
|
+
] })
|
|
2112
|
+
]
|
|
2113
|
+
}
|
|
2114
|
+
),
|
|
2115
|
+
/* @__PURE__ */ jsx(Divider, {}),
|
|
2116
|
+
/* @__PURE__ */ jsx(Box6, { sx: { p: 1 }, children: tools2.map((tool, i) => /* @__PURE__ */ jsxs(
|
|
2117
|
+
MenuItem,
|
|
2118
|
+
{
|
|
2119
|
+
onClick: () => {
|
|
2120
|
+
onOpenTool(tool.id);
|
|
2121
|
+
setMenuAnchor(null);
|
|
2122
|
+
},
|
|
2123
|
+
disableGutters: true,
|
|
2124
|
+
sx: { alignItems: "flex-start", gap: 1.25, px: 1.25, py: 1.25, mt: i === 0 ? 0 : 0.5, borderRadius: 1.5, whiteSpace: "normal" },
|
|
2125
|
+
children: [
|
|
2126
|
+
/* @__PURE__ */ jsx(ToolTile, { color: tool.color ?? "primary", children: tool.icon }),
|
|
2127
|
+
/* @__PURE__ */ jsxs(Box6, { sx: { flex: 1, minWidth: 0 }, children: [
|
|
2128
|
+
/* @__PURE__ */ jsx(Typography3, { variant: "subtitle2", sx: { fontWeight: 600, lineHeight: 1.3 }, children: tool.title }),
|
|
2129
|
+
/* @__PURE__ */ jsx(Typography3, { variant: "caption", sx: { color: "text.secondary", display: "block" }, children: tool.subtitle })
|
|
2130
|
+
] }),
|
|
2131
|
+
/* @__PURE__ */ jsxs(Stack, { direction: "row", spacing: 0.5, alignItems: "center", sx: { mt: 0.25 }, children: [
|
|
2132
|
+
/* @__PURE__ */ jsx(ToolBadge, { tool }),
|
|
2133
|
+
/* @__PURE__ */ jsx(Box6, { sx: { display: "grid", placeItems: "center", color: "text.disabled" }, children: /* @__PURE__ */ jsx(LuChevronRight, { size: 16 }) })
|
|
2134
|
+
] })
|
|
2135
|
+
]
|
|
2136
|
+
},
|
|
2137
|
+
tool.id
|
|
2138
|
+
)) })
|
|
2139
|
+
]
|
|
2140
|
+
}
|
|
2141
|
+
)
|
|
1673
2142
|
] });
|
|
1674
2143
|
}
|
|
1675
2144
|
function DevPanel(config) {
|
|
1676
2145
|
const enabled = config.enabled ?? (typeof process !== "undefined" ? process.env.NODE_ENV !== "production" : true);
|
|
1677
|
-
useEffect(() => {
|
|
1678
|
-
if (enabled) injectBaseStyles();
|
|
1679
|
-
}, [enabled]);
|
|
1680
2146
|
if (!enabled) return null;
|
|
1681
|
-
return /* @__PURE__ */ jsx(DevPanelConfigProvider, { config, children: /* @__PURE__ */ jsx(DevPanelInner, { ids: config.tools
|
|
2147
|
+
return /* @__PURE__ */ jsx(DevPanelConfigProvider, { config, children: /* @__PURE__ */ jsx(DevPanelInner, { ids: config.tools }) });
|
|
1682
2148
|
}
|
|
1683
|
-
function DevPanelInner({
|
|
1684
|
-
ids,
|
|
1685
|
-
theme
|
|
1686
|
-
}) {
|
|
2149
|
+
function DevPanelInner({ ids }) {
|
|
1687
2150
|
const tools2 = useMemo(() => resolveTools(ids), [ids]);
|
|
1688
2151
|
const [openId, setOpenId] = useState(null);
|
|
1689
2152
|
useEffect(() => {
|
|
1690
2153
|
tools2.forEach((t) => t.init?.());
|
|
1691
2154
|
}, [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
2155
|
const ActivePanel = tools2.find((t) => t.id === openId)?.Panel ?? null;
|
|
1697
|
-
return /* @__PURE__ */ jsxs(
|
|
2156
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1698
2157
|
/* @__PURE__ */ jsx(Launcher, { tools: tools2, onOpenTool: setOpenId }),
|
|
1699
2158
|
ActivePanel && /* @__PURE__ */ jsx(ActivePanel, { onClose: () => setOpenId(null) }),
|
|
1700
2159
|
tools2.map((t) => t.Overlay ? /* @__PURE__ */ jsx(t.Overlay, {}, t.id) : null)
|
|
@@ -1706,6 +2165,6 @@ registerDevLogs();
|
|
|
1706
2165
|
registerPagePerformance();
|
|
1707
2166
|
registerComponentGraph();
|
|
1708
2167
|
|
|
1709
|
-
export { DevPanel, defaultOpenInEditor, getRegisteredTools,
|
|
2168
|
+
export { DevPanel, defaultOpenInEditor, getRegisteredTools, registerTool, useDevPanelConfig };
|
|
1710
2169
|
//# sourceMappingURL=index.js.map
|
|
1711
2170
|
//# sourceMappingURL=index.js.map
|