@yuku123/z-graph-component 0.0.0-stage → 0.1.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/pages.js ADDED
@@ -0,0 +1,2186 @@
1
+ import { j as e, a as W, s as Y, f as ae, G as Ne, I as Se } from "./GraphApp-BWZfTdAD.js";
2
+ import { c as bt } from "./GraphApp-BWZfTdAD.js";
3
+ import { UserOutlined as ve, LockOutlined as Te, HomeOutlined as Ee, DashboardOutlined as Ce, PartitionOutlined as Ae, BranchesOutlined as we, HistoryOutlined as ke, CodeOutlined as Ie, DatabaseOutlined as Le, ProfileOutlined as Re, FileTextOutlined as Oe } from "@ant-design/icons";
4
+ import { useState as N, useEffect as $, useRef as te, useCallback as K, useMemo as X } from "react";
5
+ import { Typography as Me, Card as re, Space as oe, Tag as De, Row as He, Col as Pe, Form as Z, Input as le, Button as ze, message as ie } from "antd";
6
+ import { useNavigate as We } from "react-router-dom";
7
+ import "@yuku123/z-frontend-common/ui";
8
+ function Ge(t) {
9
+ const [r, o] = N({
10
+ status: "unknown",
11
+ head: null,
12
+ nodeCount: 0,
13
+ edgeCount: 0,
14
+ error: null
15
+ }), [a, d] = N(null);
16
+ return $(() => {
17
+ let p = !1;
18
+ async function S() {
19
+ try {
20
+ const [x, l] = await Promise.all([
21
+ W.health(),
22
+ W.metrics().catch(() => null)
23
+ ]);
24
+ if (p) return;
25
+ o({
26
+ status: "up",
27
+ head: x.head,
28
+ nodeCount: x.nodeCount || 0,
29
+ edgeCount: x.edgeCount || 0,
30
+ error: null
31
+ }), d(l || null);
32
+ } catch (x) {
33
+ if (p) return;
34
+ o({ status: "down", head: null, nodeCount: 0, edgeCount: 0, error: x.message }), d(null);
35
+ }
36
+ }
37
+ S();
38
+ const f = setInterval(S, 5e3);
39
+ return () => {
40
+ p = !0, clearInterval(f);
41
+ };
42
+ }, [t]), { server: r, metrics: a };
43
+ }
44
+ function je(t) {
45
+ return function() {
46
+ const { server: o, metrics: a } = Ge();
47
+ return /* @__PURE__ */ e.jsx(t, { server: o, metrics: a });
48
+ };
49
+ }
50
+ function F(t) {
51
+ const r = je(t);
52
+ return function() {
53
+ return /* @__PURE__ */ e.jsx("div", { className: "zgc", children: /* @__PURE__ */ e.jsx(r, {}) });
54
+ };
55
+ }
56
+ function qe({ server: t }) {
57
+ const [r, o] = N([]), [a, d] = N([]), [p, S] = N(null), [f, x] = N(!0), [l, C] = N(null), [j, v] = N([]), A = te(null);
58
+ $(() => {
59
+ let s = !1;
60
+ async function m() {
61
+ try {
62
+ x(!0);
63
+ const [i, c, b] = await Promise.all([
64
+ W.branches().catch(() => []),
65
+ W.commits().catch(() => []),
66
+ W.schema().catch(() => null)
67
+ ]);
68
+ o(Array.isArray(i) ? i : []), d(Array.isArray(c) ? c : []), S(b), C(null);
69
+ } catch (i) {
70
+ C(i.message);
71
+ } finally {
72
+ x(!1);
73
+ }
74
+ }
75
+ m();
76
+ }, [t.head]), $(() => {
77
+ let s = !1;
78
+ async function m() {
79
+ try {
80
+ const c = await W.metrics().catch(() => null);
81
+ if (s || !c) return;
82
+ const b = Date.now();
83
+ let E = 0;
84
+ if (A.current) {
85
+ const T = (b - A.current.ts) / 1e3;
86
+ T > 0 && (E = Math.round((c.totalRequests - A.current.total) / T * 10) / 10);
87
+ }
88
+ A.current = { ts: b, total: c.totalRequests }, v((T) => {
89
+ var y;
90
+ return [...T, { ts: b, rps: E, requests: c.totalRequests, errors: c.errorResponses, memory: ((y = c.jvmMemory) == null ? void 0 : y.usedBytes) || 0 }].slice(-60);
91
+ });
92
+ } catch {
93
+ }
94
+ }
95
+ m();
96
+ const i = setInterval(m, 5e3);
97
+ return () => {
98
+ s = !0, clearInterval(i);
99
+ };
100
+ }, []);
101
+ const k = a.slice(-5).reverse(), g = (p == null ? void 0 : p.tags) || [], h = (p == null ? void 0 : p.edges) || [], n = (p == null ? void 0 : p.indexes) || [];
102
+ return /* @__PURE__ */ e.jsxs(e.Fragment, { children: [
103
+ /* @__PURE__ */ e.jsxs("div", { className: "kpi-grid", children: [
104
+ /* @__PURE__ */ e.jsx(Q, { label: "节点数", value: t.nodeCount, icon: "N", color: "#60a5fa" }),
105
+ /* @__PURE__ */ e.jsx(Q, { label: "边数", value: t.edgeCount, icon: "E", color: "#34d399" }),
106
+ /* @__PURE__ */ e.jsx(Q, { label: "分支数", value: r.length, icon: "B", color: "#a78bfa" }),
107
+ /* @__PURE__ */ e.jsx(Q, { label: "总提交", value: a.length, icon: "C", color: "#fbbf24" })
108
+ ] }),
109
+ j.length > 1 && /* @__PURE__ */ e.jsxs("div", { className: "card", children: [
110
+ /* @__PURE__ */ e.jsx("h2", { children: "实时指标" }),
111
+ /* @__PURE__ */ e.jsxs("div", { style: { display: "grid", gridTemplateColumns: "1fr 1fr", gap: 16 }, children: [
112
+ /* @__PURE__ */ e.jsx(
113
+ ce,
114
+ {
115
+ data: j,
116
+ dataKey: "rps",
117
+ title: "请求速率 (req/s)",
118
+ color: "#60a5fa",
119
+ unit: "req/s"
120
+ }
121
+ ),
122
+ /* @__PURE__ */ e.jsx(
123
+ ce,
124
+ {
125
+ data: j,
126
+ dataKey: "memory",
127
+ title: "JVM 内存",
128
+ color: "#a78bfa",
129
+ unit: "MB",
130
+ format: (s) => Math.round(s / 1024 / 1024)
131
+ }
132
+ )
133
+ ] })
134
+ ] }),
135
+ /* @__PURE__ */ e.jsxs("div", { className: "row-2", children: [
136
+ /* @__PURE__ */ e.jsxs("div", { className: "card", children: [
137
+ /* @__PURE__ */ e.jsx("h2", { children: "Schema 概览" }),
138
+ f && /* @__PURE__ */ e.jsx("div", { className: "muted", children: "加载中…" }),
139
+ !f && g.length === 0 && h.length === 0 && /* @__PURE__ */ e.jsx("div", { className: "empty", children: "暂无 Schema,请先 CREATE TAG / CREATE EDGE" }),
140
+ g.length > 0 && /* @__PURE__ */ e.jsxs(e.Fragment, { children: [
141
+ /* @__PURE__ */ e.jsxs("h3", { style: { marginTop: 12 }, children: [
142
+ "TAG (",
143
+ g.length,
144
+ ")"
145
+ ] }),
146
+ /* @__PURE__ */ e.jsx("div", { className: "chip-list", children: g.map((s, m) => /* @__PURE__ */ e.jsx("span", { className: "chip tag-chip", children: s.Name || s.name || JSON.stringify(s) }, m)) })
147
+ ] }),
148
+ h.length > 0 && /* @__PURE__ */ e.jsxs(e.Fragment, { children: [
149
+ /* @__PURE__ */ e.jsxs("h3", { style: { marginTop: 12 }, children: [
150
+ "EDGE (",
151
+ h.length,
152
+ ")"
153
+ ] }),
154
+ /* @__PURE__ */ e.jsx("div", { className: "chip-list", children: h.map((s, m) => /* @__PURE__ */ e.jsx("span", { className: "chip edge-chip", children: s.Name || s.name || JSON.stringify(s) }, m)) })
155
+ ] }),
156
+ n.length > 0 && /* @__PURE__ */ e.jsxs(e.Fragment, { children: [
157
+ /* @__PURE__ */ e.jsxs("h3", { style: { marginTop: 12 }, children: [
158
+ "INDEX (",
159
+ n.length,
160
+ ")"
161
+ ] }),
162
+ /* @__PURE__ */ e.jsxs("table", { children: [
163
+ /* @__PURE__ */ e.jsx("thead", { children: /* @__PURE__ */ e.jsxs("tr", { children: [
164
+ /* @__PURE__ */ e.jsx("th", { children: "名称" }),
165
+ /* @__PURE__ */ e.jsx("th", { children: "类型" }),
166
+ /* @__PURE__ */ e.jsx("th", { children: "标签" })
167
+ ] }) }),
168
+ /* @__PURE__ */ e.jsx("tbody", { children: n.map((s, m) => /* @__PURE__ */ e.jsxs("tr", { children: [
169
+ /* @__PURE__ */ e.jsx("td", { className: "mono", children: s.Name || s.name || "-" }),
170
+ /* @__PURE__ */ e.jsx("td", { children: s.Type || s.type || "-" }),
171
+ /* @__PURE__ */ e.jsx("td", { children: s.Label || s.label || "-" })
172
+ ] }, m)) })
173
+ ] })
174
+ ] })
175
+ ] }),
176
+ /* @__PURE__ */ e.jsxs("div", { className: "card", children: [
177
+ /* @__PURE__ */ e.jsx("h2", { children: "快捷操作" }),
178
+ /* @__PURE__ */ e.jsxs("div", { className: "action-grid", children: [
179
+ /* @__PURE__ */ e.jsx(
180
+ ee,
181
+ {
182
+ title: "创建节点",
183
+ desc: "CREATE (n:Person {name:'Tom'})",
184
+ color: "#60a5fa"
185
+ }
186
+ ),
187
+ /* @__PURE__ */ e.jsx(
188
+ ee,
189
+ {
190
+ title: "查询数据",
191
+ desc: "MATCH (n) RETURN n LIMIT 10",
192
+ color: "#34d399"
193
+ }
194
+ ),
195
+ /* @__PURE__ */ e.jsx(
196
+ ee,
197
+ {
198
+ title: "Schema 管理",
199
+ desc: "CREATE TAG / CREATE EDGE",
200
+ color: "#a78bfa"
201
+ }
202
+ ),
203
+ /* @__PURE__ */ e.jsx(
204
+ ee,
205
+ {
206
+ title: "版本管理",
207
+ desc: "CALL db.branches() / commits",
208
+ color: "#fbbf24"
209
+ }
210
+ )
211
+ ] })
212
+ ] })
213
+ ] }),
214
+ /* @__PURE__ */ e.jsxs("div", { className: "card", children: [
215
+ /* @__PURE__ */ e.jsx("h2", { children: "最近提交" }),
216
+ f && /* @__PURE__ */ e.jsx("div", { className: "muted", children: "加载中…" }),
217
+ l && /* @__PURE__ */ e.jsx("div", { className: "error", children: l }),
218
+ !f && k.length === 0 && /* @__PURE__ */ e.jsx("div", { className: "empty", children: "还没有任何 commit" }),
219
+ !f && k.length > 0 && /* @__PURE__ */ e.jsxs("table", { children: [
220
+ /* @__PURE__ */ e.jsx("thead", { children: /* @__PURE__ */ e.jsxs("tr", { children: [
221
+ /* @__PURE__ */ e.jsx("th", { children: "Commit" }),
222
+ /* @__PURE__ */ e.jsx("th", { children: "分支" }),
223
+ /* @__PURE__ */ e.jsx("th", { children: "作者" }),
224
+ /* @__PURE__ */ e.jsx("th", { children: "说明" }),
225
+ /* @__PURE__ */ e.jsx("th", { children: "节点" }),
226
+ /* @__PURE__ */ e.jsx("th", { children: "边" }),
227
+ /* @__PURE__ */ e.jsx("th", { children: "时间" })
228
+ ] }) }),
229
+ /* @__PURE__ */ e.jsx("tbody", { children: k.map((s) => /* @__PURE__ */ e.jsxs("tr", { children: [
230
+ /* @__PURE__ */ e.jsx("td", { className: "mono", children: Y(s.id, 10) }),
231
+ /* @__PURE__ */ e.jsx("td", { children: /* @__PURE__ */ e.jsx("span", { className: "tag", children: s.branch }) }),
232
+ /* @__PURE__ */ e.jsx("td", { children: s.author }),
233
+ /* @__PURE__ */ e.jsx("td", { children: s.message }),
234
+ /* @__PURE__ */ e.jsx("td", { children: s.nodeCount }),
235
+ /* @__PURE__ */ e.jsx("td", { children: s.edgeCount }),
236
+ /* @__PURE__ */ e.jsx("td", { children: ae(s.timestamp) })
237
+ ] }, s.id)) })
238
+ ] })
239
+ ] })
240
+ ] });
241
+ }
242
+ function Q({ label: t, value: r, icon: o, color: a }) {
243
+ return /* @__PURE__ */ e.jsxs("div", { className: "kpi", children: [
244
+ /* @__PURE__ */ e.jsx("div", { className: "kpi-icon", style: { background: a + "20", color: a }, children: o }),
245
+ /* @__PURE__ */ e.jsxs("div", { className: "kpi-content", children: [
246
+ /* @__PURE__ */ e.jsx("div", { className: "kpi-value", children: r ?? "-" }),
247
+ /* @__PURE__ */ e.jsx("div", { className: "kpi-label", children: t })
248
+ ] })
249
+ ] });
250
+ }
251
+ function ee({ title: t, desc: r, color: o }) {
252
+ return /* @__PURE__ */ e.jsxs("div", { className: "action-card", style: { borderTopColor: o }, children: [
253
+ /* @__PURE__ */ e.jsx("div", { className: "action-title", children: t }),
254
+ /* @__PURE__ */ e.jsx("div", { className: "action-desc mono", children: r })
255
+ ] });
256
+ }
257
+ function ce({ data: t, dataKey: r, title: o, color: a, unit: d, format: p }) {
258
+ if (!t || t.length < 2) return null;
259
+ const S = 400, f = 120, x = 30, l = t.map((s) => p ? p(s[r]) : s[r]), C = Math.max(...l, 1), j = 0, v = C - j || 1, A = l.map((s, m) => {
260
+ const i = x + m / (l.length - 1) * (S - x * 2), c = f - x - (s - j) / v * (f - x * 2);
261
+ return { x: i, y: c, v: s };
262
+ }), k = A.map((s, m) => `${m === 0 ? "M" : "L"}${s.x},${s.y}`).join(" "), g = k + ` L${A[A.length - 1].x},${f - x} L${A[0].x},${f - x} Z`, h = l[l.length - 1], n = [0, 0.5, 1].map((s) => ({
263
+ value: Math.round(j + s * v),
264
+ y: f - x - s * (f - x * 2)
265
+ }));
266
+ return /* @__PURE__ */ e.jsxs("div", { className: "metrics-chart", children: [
267
+ /* @__PURE__ */ e.jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "baseline", marginBottom: 8 }, children: [
268
+ /* @__PURE__ */ e.jsx("span", { style: { fontSize: 13, color: "#94a3b8" }, children: o }),
269
+ /* @__PURE__ */ e.jsxs("span", { className: "mono", style: { fontSize: 18, fontWeight: 600, color: a }, children: [
270
+ h,
271
+ d ? " " + d : ""
272
+ ] })
273
+ ] }),
274
+ /* @__PURE__ */ e.jsxs("svg", { viewBox: `0 0 ${S} ${f}`, style: { width: "100%", height: f }, children: [
275
+ n.map((s, m) => /* @__PURE__ */ e.jsxs("g", { children: [
276
+ /* @__PURE__ */ e.jsx("line", { x1: x, y1: s.y, x2: S - x, y2: s.y, stroke: "#1e293b", strokeWidth: "1" }),
277
+ /* @__PURE__ */ e.jsx("text", { x: x - 4, y: s.y + 4, textAnchor: "end", fontSize: "9", fill: "#475569", children: s.value })
278
+ ] }, m)),
279
+ /* @__PURE__ */ e.jsx("path", { d: g, fill: a, fillOpacity: "0.1" }),
280
+ /* @__PURE__ */ e.jsx("path", { d: k, fill: "none", stroke: a, strokeWidth: "2", strokeLinejoin: "round" }),
281
+ /* @__PURE__ */ e.jsx("circle", { cx: A[A.length - 1].x, cy: A[A.length - 1].y, r: "3", fill: a })
282
+ ] })
283
+ ] });
284
+ }
285
+ const de = ["#3b82f6", "#10b981", "#f59e0b", "#ef4444", "#8b5cf6", "#06b6d4", "#ec4899", "#84cc16"], B = 24;
286
+ function $e({ server: t }) {
287
+ const [r, o] = N(null), [a, d] = N(!1), [p, S] = N(null), [f, x] = N(null), [l, C] = N(null), j = te(null), [v, A] = N({ width: 800, height: 500 });
288
+ $(() => {
289
+ var c;
290
+ const i = (c = j.current) == null ? void 0 : c.parentElement;
291
+ if (i) {
292
+ const b = new ResizeObserver((E) => {
293
+ for (const T of E)
294
+ A({ width: T.contentRect.width, height: Math.max(400, T.contentRect.height) });
295
+ });
296
+ return b.observe(i), () => b.disconnect();
297
+ }
298
+ }, []);
299
+ const k = K(async () => {
300
+ d(!0), S(null);
301
+ try {
302
+ const c = (await W.query("MATCH (n) RETURN n", "main") || []).map((E, T) => {
303
+ const w = E.n || E, y = typeof w == "string" ? V(w) : w;
304
+ return { id: y._id ?? T, label: y._label || "Node", props: y, x: 0, y: 0 };
305
+ });
306
+ let b = [];
307
+ try {
308
+ const E = await W.query("SHOW EDGES", "main"), T = Array.isArray(E) ? E : [];
309
+ for (const w of T) {
310
+ const y = w.Name || w.name || "";
311
+ if (y)
312
+ try {
313
+ const L = await W.query(`MATCH (a)-[r:${y}]->(b) RETURN a, r, b`, "main");
314
+ for (const R of L || []) {
315
+ const O = typeof R.a == "string" ? V(R.a) : R.a, z = typeof R.b == "string" ? V(R.b) : R.b, D = typeof R.r == "string" ? Ue(R.r) : R.r;
316
+ b.push({
317
+ source: O._id,
318
+ target: z._id,
319
+ type: y,
320
+ props: D
321
+ });
322
+ }
323
+ } catch {
324
+ }
325
+ }
326
+ if (T.length === 0 && c.length > 0)
327
+ for (const w of ["KNOWS", "WORKS_AT", "LIKES", "FOLLOWS"])
328
+ try {
329
+ const y = await W.query(`MATCH (a)-[r:${w}]->(b) RETURN a, r, b`, "main");
330
+ if (Array.isArray(y) && y.length > 0)
331
+ for (const L of y) {
332
+ const R = typeof L.a == "string" ? V(L.a) : L.a, O = typeof L.b == "string" ? V(L.b) : L.b;
333
+ b.push({ source: R._id, target: O._id, type: w, props: {} });
334
+ }
335
+ } catch {
336
+ }
337
+ } catch {
338
+ }
339
+ o({ nodes: c, edges: b });
340
+ } catch (i) {
341
+ S(i.message);
342
+ } finally {
343
+ d(!1);
344
+ }
345
+ }, []);
346
+ $(() => {
347
+ k();
348
+ }, [t.head]), $(() => {
349
+ if (!r || r.nodes.length === 0) {
350
+ C(null);
351
+ return;
352
+ }
353
+ const i = r.nodes.map((T, w) => ({
354
+ ...T,
355
+ x: v.width / 2 + (Math.random() - 0.5) * 200,
356
+ y: v.height / 2 + (Math.random() - 0.5) * 200,
357
+ vx: 0,
358
+ vy: 0
359
+ })), c = r.edges.map((T) => ({
360
+ ...T,
361
+ sourceIdx: i.findIndex((w) => w.id === T.source),
362
+ targetIdx: i.findIndex((w) => w.id === T.target)
363
+ })).filter((T) => T.sourceIdx >= 0 && T.targetIdx >= 0), b = v.width / 2, E = v.height / 2;
364
+ for (let T = 0; T < 120; T++) {
365
+ const w = 1 - T / 120;
366
+ for (let y = 0; y < i.length; y++)
367
+ for (let L = y + 1; L < i.length; L++) {
368
+ let R = i[L].x - i[y].x, O = i[L].y - i[y].y, z = Math.sqrt(R * R + O * O) || 1, D = 800 * w / z;
369
+ i[y].vx -= R / z * D, i[y].vy -= O / z * D, i[L].vx += R / z * D, i[L].vy += O / z * D;
370
+ }
371
+ for (const y of c) {
372
+ const L = i[y.sourceIdx], R = i[y.targetIdx];
373
+ let O = R.x - L.x, z = R.y - L.y, D = Math.sqrt(O * O + z * z) || 1, G = (D - 120) * 0.05 * w;
374
+ L.vx += O / D * G, L.vy += z / D * G, R.vx -= O / D * G, R.vy -= z / D * G;
375
+ }
376
+ for (const y of i)
377
+ y.vx += (b - y.x) * 0.01 * w, y.vy += (E - y.y) * 0.01 * w;
378
+ for (const y of i)
379
+ y.vx *= 0.6, y.vy *= 0.6, y.x += y.vx, y.y += y.vy, y.x = Math.max(B, Math.min(v.width - B, y.x)), y.y = Math.max(B, Math.min(v.height - B, y.y));
380
+ }
381
+ C({ nodes: i, edges: c });
382
+ }, [r, v]);
383
+ const g = {};
384
+ let h = 0;
385
+ function n(i) {
386
+ return g[i] || (g[i] = de[h++ % de.length]), g[i];
387
+ }
388
+ function s(i, c) {
389
+ const b = n(i.label), E = f === c, T = (l == null ? void 0 : l.edges.filter((y) => y.sourceIdx === c || y.targetIdx === c)) || [], w = f !== null && !E && !T.some((y) => y.sourceIdx === f || y.targetIdx === f);
390
+ return /* @__PURE__ */ e.jsxs(
391
+ "g",
392
+ {
393
+ transform: `translate(${i.x},${i.y})`,
394
+ style: { cursor: "pointer", opacity: w ? 0.25 : 1 },
395
+ onClick: () => x(E ? null : c),
396
+ children: [
397
+ /* @__PURE__ */ e.jsx("circle", { r: B, fill: b, stroke: E ? "#fff" : "#0f172a", strokeWidth: E ? 3 : 2 }),
398
+ /* @__PURE__ */ e.jsx("text", { textAnchor: "middle", dy: "0.35em", fill: "#fff", fontSize: "11", fontWeight: "600", style: { pointerEvents: "none" }, children: i.label.substring(0, 4) }),
399
+ /* @__PURE__ */ e.jsx("text", { textAnchor: "middle", dy: B + 14, fill: "#94a3b8", fontSize: "10", style: { pointerEvents: "none" }, children: i.props.name || i.props._id || c })
400
+ ]
401
+ },
402
+ c
403
+ );
404
+ }
405
+ function m(i, c) {
406
+ const b = l.nodes[i.sourceIdx], E = l.nodes[i.targetIdx];
407
+ if (!b || !E) return null;
408
+ const T = E.x - b.x, w = E.y - b.y, y = Math.sqrt(T * T + w * w) || 1, L = T / y, R = w / y, O = b.x + L * B, z = b.y + R * B, D = E.x - L * B, G = E.y - R * B, u = f !== null && (i.sourceIdx === f || i.targetIdx === f), P = f !== null && !u, I = 10, M = Math.atan2(G - z, D - O), H = D - I * Math.cos(M - 0.35), q = G - I * Math.sin(M - 0.35), se = D - I * Math.cos(M + 0.35), be = G - I * Math.sin(M + 0.35);
409
+ return /* @__PURE__ */ e.jsxs("g", { style: { opacity: P ? 0.15 : 1 }, children: [
410
+ /* @__PURE__ */ e.jsx("line", { x1: O, y1: z, x2: D, y2: G, stroke: u ? "#60a5fa" : "#475569", strokeWidth: u ? 2.5 : 1.5 }),
411
+ /* @__PURE__ */ e.jsx("polygon", { points: `${D},${G} ${H},${q} ${se},${be}`, fill: u ? "#60a5fa" : "#475569" }),
412
+ i.type && /* @__PURE__ */ e.jsx("text", { x: (O + D) / 2, y: (z + G) / 2 - 6, textAnchor: "middle", fill: "#64748b", fontSize: "9", style: { pointerEvents: "none" }, children: i.type })
413
+ ] }, c);
414
+ }
415
+ return /* @__PURE__ */ e.jsxs(e.Fragment, { children: [
416
+ /* @__PURE__ */ e.jsxs("div", { className: "card", children: [
417
+ /* @__PURE__ */ e.jsxs("div", { className: "toolbar", children: [
418
+ /* @__PURE__ */ e.jsx("button", { className: "primary", onClick: k, disabled: a, children: a ? "加载中…" : "刷新图" }),
419
+ /* @__PURE__ */ e.jsx("span", { className: "muted", children: l ? `${l.nodes.length} 节点 · ${l.edges.length} 边` : "无数据" }),
420
+ f !== null && (l == null ? void 0 : l.nodes[f]) && /* @__PURE__ */ e.jsxs("span", { className: "tag", style: { marginLeft: 8 }, children: [
421
+ "选中: ",
422
+ l.nodes[f].label,
423
+ " (",
424
+ l.nodes[f].props.name || l.nodes[f].props._id,
425
+ ")"
426
+ ] })
427
+ ] }),
428
+ p && /* @__PURE__ */ e.jsx("div", { className: "error", style: { marginTop: 8 }, children: p })
429
+ ] }),
430
+ /* @__PURE__ */ e.jsxs("div", { className: "card", style: { padding: 0, overflow: "hidden" }, children: [
431
+ (!l || l.nodes.length === 0) && !a && /* @__PURE__ */ e.jsx("div", { className: "empty", children: "暂无图数据。请先在 Cypher 查询页创建节点和边。" }),
432
+ /* @__PURE__ */ e.jsxs(
433
+ "svg",
434
+ {
435
+ ref: j,
436
+ width: "100%",
437
+ height: v.height,
438
+ style: { background: "#0f172a", display: l != null && l.nodes.length ? "block" : "none" },
439
+ children: [
440
+ /* @__PURE__ */ e.jsx("defs", { children: /* @__PURE__ */ e.jsx("pattern", { id: "grid", width: "40", height: "40", patternUnits: "userSpaceOnUse", children: /* @__PURE__ */ e.jsx("path", { d: "M 40 0 L 0 0 0 40", fill: "none", stroke: "#1e293b", strokeWidth: "0.5" }) }) }),
441
+ /* @__PURE__ */ e.jsx("rect", { width: "100%", height: "100%", fill: "url(#grid)" }),
442
+ /* @__PURE__ */ e.jsx("g", { children: l == null ? void 0 : l.edges.map((i, c) => m(i, c)) }),
443
+ /* @__PURE__ */ e.jsx("g", { children: l == null ? void 0 : l.nodes.map((i, c) => s(i, c)) })
444
+ ]
445
+ }
446
+ )
447
+ ] }),
448
+ l && l.nodes.length > 0 && /* @__PURE__ */ e.jsxs("div", { className: "card", children: [
449
+ /* @__PURE__ */ e.jsx("h2", { children: "图例" }),
450
+ /* @__PURE__ */ e.jsx("div", { className: "chip-list", children: [...new Set(l.nodes.map((i) => i.label))].map((i) => /* @__PURE__ */ e.jsxs("span", { className: "chip", style: { borderColor: n(i), color: n(i) }, children: [
451
+ /* @__PURE__ */ e.jsx("span", { style: { width: 8, height: 8, borderRadius: "50%", background: n(i), display: "inline-block", marginRight: 4 } }),
452
+ i
453
+ ] }, i)) })
454
+ ] })
455
+ ] });
456
+ }
457
+ function V(t) {
458
+ const r = t.match(/\((\d+):/), o = t.match(/:\[(\w+)\]/), a = t.match(/\{(.+)\}/), d = { _id: r ? parseInt(r[1]) : 0, _label: o ? o[1] : "Node" };
459
+ return a && a[1].split(",").forEach((p) => {
460
+ const [S, f] = p.split("=").map((x) => x.trim());
461
+ S && f && (d[S] = isNaN(f) ? f.replace(/^'|'$/g, "") : Number(f));
462
+ }), d;
463
+ }
464
+ function Ue(t) {
465
+ const r = t.match(/\}\s*\{(.*?)\}/) || t.match(/\{(.*)\}/), o = {};
466
+ return r && r[1] && r[1].split(",").forEach((a) => {
467
+ const [d, p] = a.split("=").map((S) => S.trim());
468
+ d && p && (o[d] = isNaN(p) ? p.replace(/^'|'$/g, "") : Number(p));
469
+ }), o;
470
+ }
471
+ function Be({ server: t }) {
472
+ const [r, o] = N([]), [a, d] = N({}), [p, S] = N([]), [f, x] = N(!0), [l, C] = N(null);
473
+ $(() => {
474
+ let v = !1;
475
+ async function A() {
476
+ try {
477
+ x(!0);
478
+ const [k, g, h] = await Promise.all([
479
+ W.branches(),
480
+ W.commits(),
481
+ W.query("CALL db.branches()").catch(() => [])
482
+ ]), n = Array.isArray(k) ? k : k && k.Name ? [k.Name] : [];
483
+ o(n), S(Array.isArray(g) ? g : []);
484
+ const s = {};
485
+ (Array.isArray(h) ? h : []).forEach((m) => {
486
+ m && m.Name && (s[m.Name] = m);
487
+ }), d(s), C(null);
488
+ } catch (k) {
489
+ C(k.message);
490
+ } finally {
491
+ x(!1);
492
+ }
493
+ }
494
+ A();
495
+ }, [t.head]);
496
+ const j = p.reduce((v, A) => (v.has(A.branch) || v.set(A.branch, []), v.get(A.branch).push(A), v), /* @__PURE__ */ new Map());
497
+ return /* @__PURE__ */ e.jsxs(e.Fragment, { children: [
498
+ /* @__PURE__ */ e.jsxs("div", { className: "card", children: [
499
+ /* @__PURE__ */ e.jsx("h2", { children: "分支总览" }),
500
+ /* @__PURE__ */ e.jsx("div", { className: "muted", children: "每个分支指向一个 commit head;切换分支不会丢历史。" }),
501
+ f && /* @__PURE__ */ e.jsx("div", { className: "muted", children: "加载中…" }),
502
+ l && /* @__PURE__ */ e.jsx("div", { className: "error", children: l }),
503
+ !f && r.length === 0 && /* @__PURE__ */ e.jsx("div", { className: "empty", children: "尚无分支" }),
504
+ !f && r.length > 0 && /* @__PURE__ */ e.jsxs("table", { children: [
505
+ /* @__PURE__ */ e.jsx("thead", { children: /* @__PURE__ */ e.jsxs("tr", { children: [
506
+ /* @__PURE__ */ e.jsx("th", { children: "分支" }),
507
+ /* @__PURE__ */ e.jsx("th", { children: "Head commit" }),
508
+ /* @__PURE__ */ e.jsx("th", { children: "提交数" }),
509
+ /* @__PURE__ */ e.jsx("th", { children: "节点" }),
510
+ /* @__PURE__ */ e.jsx("th", { children: "边" })
511
+ ] }) }),
512
+ /* @__PURE__ */ e.jsx("tbody", { children: r.map((v) => {
513
+ var g;
514
+ const A = (g = a[v]) == null ? void 0 : g.Head, k = p.find((h) => h.id === A);
515
+ return /* @__PURE__ */ e.jsxs("tr", { children: [
516
+ /* @__PURE__ */ e.jsx("td", { children: /* @__PURE__ */ e.jsx("span", { className: "tag", children: v }) }),
517
+ /* @__PURE__ */ e.jsx("td", { className: "mono", children: Y(A, 12) || "-" }),
518
+ /* @__PURE__ */ e.jsx("td", { children: (j.get(v) || []).length }),
519
+ /* @__PURE__ */ e.jsx("td", { children: k ? k.nodeCount : "-" }),
520
+ /* @__PURE__ */ e.jsx("td", { children: k ? k.edgeCount : "-" })
521
+ ] }, v);
522
+ }) })
523
+ ] })
524
+ ] }),
525
+ /* @__PURE__ */ e.jsxs("div", { className: "card", children: [
526
+ /* @__PURE__ */ e.jsx("h2", { children: "操作提示" }),
527
+ /* @__PURE__ */ e.jsxs("ul", { className: "muted", style: { lineHeight: 1.8 }, children: [
528
+ /* @__PURE__ */ e.jsxs("li", { children: [
529
+ "在 Cypher 查询页执行 ",
530
+ /* @__PURE__ */ e.jsx("code", { className: "mono", children: "CALL db.branches()" }),
531
+ " / ",
532
+ /* @__PURE__ */ e.jsx("code", { className: "mono", children: "CALL db.commits()" }),
533
+ " 可以拿到结构化版本元数据。"
534
+ ] }),
535
+ /* @__PURE__ */ e.jsx("li", { children: "创建/合并/切换分支通过 Java API 或扩展控制面 endpoint(后续版本)。" }),
536
+ /* @__PURE__ */ e.jsxs("li", { children: [
537
+ 'HEAD 提交 ID 可在"提交历史"页找到,搭配 ',
538
+ /* @__PURE__ */ e.jsx("code", { className: "mono", children: "?commit=<id>" }),
539
+ " 即可对历史快照做只读查询。"
540
+ ] })
541
+ ] })
542
+ ] })
543
+ ] });
544
+ }
545
+ const he = [
546
+ "#60a5fa",
547
+ // blue
548
+ "#34d399",
549
+ // green
550
+ "#fbbf24",
551
+ // amber
552
+ "#a78bfa",
553
+ // purple
554
+ "#f87171",
555
+ // red
556
+ "#67e8f9",
557
+ // cyan
558
+ "#fb923c",
559
+ // orange
560
+ "#f472b6"
561
+ // pink
562
+ ];
563
+ function Fe({ server: t }) {
564
+ const [r, o] = N([]), [a, d] = N(!0), [p, S] = N(null), [f, x] = N(""), [l, C] = N(""), [j, v] = N(null);
565
+ $(() => {
566
+ let g = !1;
567
+ async function h() {
568
+ try {
569
+ d(!0);
570
+ const n = await W.commits();
571
+ o(Array.isArray(n) ? n : []), S(null);
572
+ } catch (n) {
573
+ S(n.message);
574
+ } finally {
575
+ d(!1);
576
+ }
577
+ }
578
+ h();
579
+ }, [t.head]);
580
+ const A = X(
581
+ () => Array.from(new Set(r.map((g) => g.branch))),
582
+ [r]
583
+ ), k = X(
584
+ () => r.filter((g) => !f || g.branch === f).filter((g) => !l || (g.message || "").toLowerCase().includes(l.toLowerCase()) || (g.author || "").toLowerCase().includes(l.toLowerCase()) || (g.id || "").startsWith(l)),
585
+ [r, f, l]
586
+ );
587
+ return /* @__PURE__ */ e.jsxs(e.Fragment, { children: [
588
+ /* @__PURE__ */ e.jsxs("div", { className: "card", children: [
589
+ /* @__PURE__ */ e.jsxs("div", { className: "toolbar", style: { marginBottom: 12 }, children: [
590
+ /* @__PURE__ */ e.jsxs("select", { value: f, onChange: (g) => x(g.target.value), children: [
591
+ /* @__PURE__ */ e.jsx("option", { value: "", children: "所有分支" }),
592
+ A.map((g) => /* @__PURE__ */ e.jsx("option", { value: g, children: g }, g))
593
+ ] }),
594
+ /* @__PURE__ */ e.jsx(
595
+ "input",
596
+ {
597
+ placeholder: "搜索 commit message / author / id",
598
+ value: l,
599
+ onChange: (g) => C(g.target.value),
600
+ style: { flex: 1 }
601
+ }
602
+ ),
603
+ /* @__PURE__ */ e.jsx("button", { onClick: () => {
604
+ x(""), C(""), v(null);
605
+ }, children: "清空" })
606
+ ] }),
607
+ a && /* @__PURE__ */ e.jsx("div", { className: "muted", children: "加载中…" }),
608
+ p && /* @__PURE__ */ e.jsx("div", { className: "error-banner", children: p }),
609
+ !a && k.length === 0 && /* @__PURE__ */ e.jsx("div", { className: "empty", children: "没有匹配的 commit" }),
610
+ !a && k.length > 0 && /* @__PURE__ */ e.jsx(
611
+ _e,
612
+ {
613
+ commits: k,
614
+ branches: A,
615
+ selected: j,
616
+ onSelect: v
617
+ }
618
+ )
619
+ ] }),
620
+ j && /* @__PURE__ */ e.jsxs("div", { className: "card", children: [
621
+ /* @__PURE__ */ e.jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "flex-start" }, children: [
622
+ /* @__PURE__ */ e.jsxs("div", { style: { flex: 1 }, children: [
623
+ /* @__PURE__ */ e.jsxs("h2", { style: { margin: "0 0 8px" }, children: [
624
+ /* @__PURE__ */ e.jsx("span", { className: "mono", style: { color: _(A, j.branch) }, children: Y(j.id, 12) }),
625
+ " ",
626
+ "提交详情"
627
+ ] }),
628
+ /* @__PURE__ */ e.jsxs("div", { style: { marginBottom: 8 }, children: [
629
+ /* @__PURE__ */ e.jsx("span", { className: "tag", style: { marginRight: 8 }, children: j.branch }),
630
+ /* @__PURE__ */ e.jsx("span", { className: "muted", children: ae(j.timestamp) })
631
+ ] }),
632
+ /* @__PURE__ */ e.jsxs("div", { style: { marginBottom: 4 }, children: [
633
+ /* @__PURE__ */ e.jsx("strong", { children: "作者:" }),
634
+ " ",
635
+ j.author
636
+ ] }),
637
+ /* @__PURE__ */ e.jsxs("div", { style: { marginBottom: 4 }, children: [
638
+ /* @__PURE__ */ e.jsx("strong", { children: "说明:" }),
639
+ " ",
640
+ j.message
641
+ ] }),
642
+ /* @__PURE__ */ e.jsxs("div", { style: { marginBottom: 4 }, children: [
643
+ /* @__PURE__ */ e.jsx("strong", { children: "父节点:" }),
644
+ " ",
645
+ (j.parents || []).map((g, h) => /* @__PURE__ */ e.jsx("span", { className: "mono", style: { marginRight: 8 }, children: Y(g, 12) }, h)) || "-"
646
+ ] }),
647
+ /* @__PURE__ */ e.jsxs("div", { style: { marginBottom: 8 }, children: [
648
+ /* @__PURE__ */ e.jsx("strong", { children: "变更:" }),
649
+ /* @__PURE__ */ e.jsxs("span", { className: "tag ok", style: { marginLeft: 4 }, children: [
650
+ j.nodeCount,
651
+ " 节点"
652
+ ] }),
653
+ /* @__PURE__ */ e.jsxs("span", { className: "tag alt", style: { marginLeft: 4 }, children: [
654
+ j.edgeCount,
655
+ " 边"
656
+ ] })
657
+ ] }),
658
+ /* @__PURE__ */ e.jsxs("div", { style: { marginBottom: 8 }, children: [
659
+ /* @__PURE__ */ e.jsx("strong", { children: "完整 ID:" }),
660
+ /* @__PURE__ */ e.jsx("code", { className: "mono", style: { fontSize: 11, color: "#94a3b8", wordBreak: "break-all" }, children: j.id })
661
+ ] })
662
+ ] }),
663
+ /* @__PURE__ */ e.jsx("button", { onClick: () => v(null), children: "✕" })
664
+ ] }),
665
+ /* @__PURE__ */ e.jsxs("div", { style: { marginTop: 12 }, children: [
666
+ /* @__PURE__ */ e.jsx("strong", { children: "按此 commit 查询:" }),
667
+ /* @__PURE__ */ e.jsx("pre", { className: "results mono", style: { marginTop: 4, fontSize: 12 }, children: `GET /query?commit=${j.id}&cypher=MATCH%20(n)%20RETURN%20n%20LIMIT%2010
668
+ -- 或者在 Cypher 查询页切到 "指定 commit" 模式` })
669
+ ] })
670
+ ] }),
671
+ /* @__PURE__ */ e.jsxs("div", { className: "card", children: [
672
+ /* @__PURE__ */ e.jsx("h2", { children: "如何按 commit 查询" }),
673
+ /* @__PURE__ */ e.jsx("pre", { className: "results", children: `GET /query?commit=<commitId>&cypher=MATCH%20(n)%20RETURN%20n%20LIMIT%2010
674
+ -- 或者在 Cypher 查询页切到 "指定 commit" 模式` })
675
+ ] })
676
+ ] });
677
+ }
678
+ function _(t, r) {
679
+ const o = t.indexOf(r);
680
+ return he[o % he.length];
681
+ }
682
+ function _e({ commits: t, branches: r, selected: o, onSelect: a }) {
683
+ const d = X(
684
+ () => [...t].sort((h, n) => (n.timestamp || 0) - (h.timestamp || 0)),
685
+ [t]
686
+ ), p = 130, S = 70, f = 7, x = 30, l = 50, C = 140, j = X(() => {
687
+ const h = /* @__PURE__ */ new Map(), n = [...r].sort((s, m) => s === "main" ? -1 : m === "main" ? 1 : r.indexOf(s) - r.indexOf(m));
688
+ return n.forEach((s, m) => h.set(s, m)), { lanes: h, totalLanes: n.length };
689
+ }, [r]), v = X(() => {
690
+ const h = /* @__PURE__ */ new Map();
691
+ return d.forEach((n, s) => {
692
+ const m = j.lanes.get(n.branch) || 0;
693
+ h.set(n.id, {
694
+ col: s,
695
+ x: x + s * p + p / 2,
696
+ y: l + m * S + S / 2,
697
+ lane: m,
698
+ branch: n.branch
699
+ });
700
+ }), h;
701
+ }, [d, j]), A = X(() => {
702
+ const h = [];
703
+ for (const n of d) {
704
+ const s = v.get(n.id);
705
+ if (!s) continue;
706
+ const m = n.parents || [];
707
+ m.forEach((i, c) => {
708
+ const b = v.get(i);
709
+ b && h.push({
710
+ from: s,
711
+ to: b,
712
+ color: _(r, n.branch),
713
+ isMainParent: c === 0,
714
+ isMerge: m.length > 1
715
+ });
716
+ });
717
+ }
718
+ return h;
719
+ }, [d, v, j, r]), k = x + d.length * p + C, g = l + j.totalLanes * S + 30;
720
+ return /* @__PURE__ */ e.jsxs("div", { className: "commit-flow-graph", style: { overflowX: "auto", overflowY: "hidden", padding: "12px 0" }, children: [
721
+ /* @__PURE__ */ e.jsxs("div", { style: { minWidth: k, position: "relative" }, children: [
722
+ /* @__PURE__ */ e.jsxs(
723
+ "svg",
724
+ {
725
+ width: k,
726
+ height: g,
727
+ style: { position: "absolute", top: 0, left: 0 },
728
+ children: [
729
+ /* @__PURE__ */ e.jsxs("defs", { children: [
730
+ /* @__PURE__ */ e.jsx(
731
+ "marker",
732
+ {
733
+ id: "arrowhead",
734
+ markerWidth: "10",
735
+ markerHeight: "10",
736
+ refX: "8",
737
+ refY: "3",
738
+ orient: "auto",
739
+ markerUnits: "strokeWidth",
740
+ children: /* @__PURE__ */ e.jsx("path", { d: "M0,0 L0,6 L9,3 z", fill: "#475569" })
741
+ }
742
+ ),
743
+ /* @__PURE__ */ e.jsx(
744
+ "marker",
745
+ {
746
+ id: "arrowhead-active",
747
+ markerWidth: "10",
748
+ markerHeight: "10",
749
+ refX: "8",
750
+ refY: "3",
751
+ orient: "auto",
752
+ markerUnits: "strokeWidth",
753
+ children: /* @__PURE__ */ e.jsx("path", { d: "M0,0 L0,6 L9,3 z", fill: "#60a5fa" })
754
+ }
755
+ )
756
+ ] }),
757
+ [...j.lanes.entries()].map(([h, n]) => {
758
+ const s = l + n * S + S / 2;
759
+ return /* @__PURE__ */ e.jsx("g", { children: /* @__PURE__ */ e.jsx(
760
+ "line",
761
+ {
762
+ x1: x - 10,
763
+ y1: s,
764
+ x2: x + d.length * p + 10,
765
+ y2: s,
766
+ stroke: _(r, h),
767
+ strokeWidth: 1.5,
768
+ strokeDasharray: "6,4",
769
+ opacity: 0.4
770
+ }
771
+ ) }, h);
772
+ }),
773
+ /* @__PURE__ */ e.jsx(
774
+ "line",
775
+ {
776
+ x1: x - 10,
777
+ y1: l - 20,
778
+ x2: x + d.length * p - 10,
779
+ y2: l - 20,
780
+ stroke: "#475569",
781
+ strokeWidth: 1,
782
+ markerEnd: "url(#arrowhead)"
783
+ }
784
+ ),
785
+ /* @__PURE__ */ e.jsx(
786
+ "text",
787
+ {
788
+ x: x - 5,
789
+ y: l - 25,
790
+ fontSize: 11,
791
+ fill: "#64748b",
792
+ children: "旧"
793
+ }
794
+ ),
795
+ A.map((h, n) => {
796
+ var P, I;
797
+ const { from: s, to: m, color: i, isMerge: c, isMainParent: b } = h, E = (o == null ? void 0 : o.id) === ((P = s.commit) == null ? void 0 : P.id) || (o == null ? void 0 : o.id) === ((I = m.commit) == null ? void 0 : I.id), T = s.x - f - 2, w = s.y, y = m.x + f + 2, L = m.y;
798
+ if (s.lane === m.lane)
799
+ return /* @__PURE__ */ e.jsx(
800
+ "line",
801
+ {
802
+ x1: T,
803
+ y1: w,
804
+ x2: y,
805
+ y2: L,
806
+ stroke: E ? "#60a5fa" : i,
807
+ strokeWidth: E ? 2.5 : 2,
808
+ markerEnd: E ? "url(#arrowhead-active)" : "url(#arrowhead)"
809
+ },
810
+ n
811
+ );
812
+ const R = y - T, O = T + R * 0.3, z = w, D = y - R * 0.3, u = `M ${T},${w} C ${O},${z} ${D},${L} ${y},${L}`;
813
+ return /* @__PURE__ */ e.jsx(
814
+ "path",
815
+ {
816
+ d: u,
817
+ stroke: E ? "#60a5fa" : i,
818
+ strokeWidth: E ? 2.5 : c && !b ? 1.5 : 2,
819
+ strokeDasharray: c && !b ? "4,3" : "0",
820
+ fill: "none",
821
+ opacity: c && !b ? 0.6 : 1,
822
+ markerEnd: E ? "url(#arrowhead-active)" : "url(#arrowhead)"
823
+ },
824
+ n
825
+ );
826
+ }),
827
+ d.map((h) => {
828
+ const n = v.get(h.id);
829
+ if (!n) return null;
830
+ const s = (h.parents || []).length > 1, m = (o == null ? void 0 : o.id) === h.id, i = _(r, h.branch), c = m ? f + 2 : f;
831
+ return s ? /* @__PURE__ */ e.jsxs("g", { children: [
832
+ /* @__PURE__ */ e.jsx(
833
+ "polygon",
834
+ {
835
+ points: `${n.x},${n.y - c} ${n.x + c},${n.y} ${n.x},${n.y + c} ${n.x - c},${n.y}`,
836
+ fill: i,
837
+ stroke: m ? "#fff" : "#0b1220",
838
+ strokeWidth: m ? 2 : 1.5,
839
+ style: { cursor: "pointer" },
840
+ onClick: () => a(m ? null : h)
841
+ }
842
+ ),
843
+ m && /* @__PURE__ */ e.jsx(
844
+ "circle",
845
+ {
846
+ cx: n.x,
847
+ cy: n.y,
848
+ r: c + 4,
849
+ fill: "none",
850
+ stroke: i,
851
+ strokeWidth: 1,
852
+ opacity: 0.5
853
+ }
854
+ )
855
+ ] }, h.id) : /* @__PURE__ */ e.jsxs("g", { children: [
856
+ /* @__PURE__ */ e.jsx(
857
+ "circle",
858
+ {
859
+ cx: n.x,
860
+ cy: n.y,
861
+ r: c,
862
+ fill: i,
863
+ stroke: m ? "#fff" : "#0b1220",
864
+ strokeWidth: m ? 2 : 1.5,
865
+ style: { cursor: "pointer" },
866
+ onClick: () => a(m ? null : h)
867
+ }
868
+ ),
869
+ m && /* @__PURE__ */ e.jsx(
870
+ "circle",
871
+ {
872
+ cx: n.x,
873
+ cy: n.y,
874
+ r: c + 4,
875
+ fill: "none",
876
+ stroke: i,
877
+ strokeWidth: 1,
878
+ opacity: 0.5
879
+ }
880
+ )
881
+ ] }, h.id);
882
+ }),
883
+ [...j.lanes.entries()].map(([h, n]) => {
884
+ const s = l + n * S + S / 2, m = x + d.length * p + 10, i = _(r, h), b = d.filter((E) => E.branch === h)[0];
885
+ return /* @__PURE__ */ e.jsxs("g", { children: [
886
+ /* @__PURE__ */ e.jsx(
887
+ "line",
888
+ {
889
+ x1: m - 10,
890
+ y1: s,
891
+ x2: m + 10,
892
+ y2: s,
893
+ stroke: i,
894
+ strokeWidth: 2
895
+ }
896
+ ),
897
+ /* @__PURE__ */ e.jsx(
898
+ "rect",
899
+ {
900
+ x: m + 12,
901
+ y: s - 11,
902
+ width: Math.max(60, h.length * 8 + 16),
903
+ height: 22,
904
+ rx: 4,
905
+ fill: i + "20",
906
+ stroke: i,
907
+ strokeWidth: 1.5,
908
+ style: { cursor: "pointer" },
909
+ onClick: () => b && a(b)
910
+ }
911
+ ),
912
+ /* @__PURE__ */ e.jsx(
913
+ "text",
914
+ {
915
+ x: m + 22,
916
+ y: s + 4,
917
+ fontSize: 12,
918
+ fill: i,
919
+ fontFamily: "'SFMono-Regular', Menlo, Consolas, monospace",
920
+ fontWeight: 600,
921
+ style: { cursor: "pointer" },
922
+ onClick: () => b && a(b),
923
+ children: h
924
+ }
925
+ )
926
+ ] }, h);
927
+ }),
928
+ [...j.lanes.entries()].map(([h, n]) => {
929
+ const s = l + n * S + S / 2, m = _(r, h);
930
+ return /* @__PURE__ */ e.jsx(
931
+ "text",
932
+ {
933
+ x: 5,
934
+ y: s + 4,
935
+ fontSize: 11,
936
+ fill: m,
937
+ fontFamily: "'SFMono-Regular', Menlo, Consolas, monospace",
938
+ children: h
939
+ },
940
+ `${h}-label`
941
+ );
942
+ })
943
+ ]
944
+ }
945
+ ),
946
+ /* @__PURE__ */ e.jsx("div", { style: { position: "relative", pointerEvents: "none" }, children: d.map((h, n) => {
947
+ const s = v.get(h.id);
948
+ if (!s) return null;
949
+ const m = (o == null ? void 0 : o.id) === h.id;
950
+ return /* @__PURE__ */ e.jsxs(
951
+ "div",
952
+ {
953
+ onClick: () => a(m ? null : h),
954
+ style: {
955
+ position: "absolute",
956
+ left: s.x - p / 2 + 12,
957
+ top: s.y - 26,
958
+ width: p - 14,
959
+ fontSize: 11,
960
+ color: m ? "#f8fafc" : "#cbd5e1",
961
+ pointerEvents: "auto",
962
+ cursor: "pointer",
963
+ textAlign: "left"
964
+ },
965
+ children: [
966
+ /* @__PURE__ */ e.jsx(
967
+ "div",
968
+ {
969
+ className: "mono",
970
+ style: {
971
+ fontSize: 10,
972
+ color: _(r, h.branch),
973
+ fontWeight: 600,
974
+ whiteSpace: "nowrap",
975
+ overflow: "hidden",
976
+ textOverflow: "ellipsis"
977
+ },
978
+ title: h.id,
979
+ children: Y(h.id, 7)
980
+ }
981
+ ),
982
+ /* @__PURE__ */ e.jsx(
983
+ "div",
984
+ {
985
+ style: {
986
+ whiteSpace: "nowrap",
987
+ overflow: "hidden",
988
+ textOverflow: "ellipsis"
989
+ },
990
+ title: h.message,
991
+ children: h.message
992
+ }
993
+ ),
994
+ /* @__PURE__ */ e.jsx("div", { style: { fontSize: 9, color: "#64748b", whiteSpace: "nowrap" }, children: ae(h.timestamp) })
995
+ ]
996
+ },
997
+ h.id
998
+ );
999
+ }) })
1000
+ ] }),
1001
+ /* @__PURE__ */ e.jsxs("div", { style: { marginTop: 16, display: "flex", flexWrap: "wrap", gap: 12, padding: "8px 0", borderTop: "1px solid #1e293b" }, children: [
1002
+ r.map((h) => /* @__PURE__ */ e.jsxs("div", { style: { display: "flex", alignItems: "center", gap: 6, fontSize: 12 }, children: [
1003
+ /* @__PURE__ */ e.jsx("span", { style: {
1004
+ display: "inline-block",
1005
+ width: 14,
1006
+ height: 3,
1007
+ background: _(r, h)
1008
+ } }),
1009
+ /* @__PURE__ */ e.jsx("span", { className: "mono", children: h }),
1010
+ /* @__PURE__ */ e.jsxs("span", { className: "muted", children: [
1011
+ "(",
1012
+ d.filter((n) => n.branch === h).length,
1013
+ " commits)"
1014
+ ] })
1015
+ ] }, h)),
1016
+ /* @__PURE__ */ e.jsx("div", { style: { marginLeft: "auto", fontSize: 11, color: "#64748b" }, children: "💡 点击 commit 或分支标签查看详情 · 时间轴 ←" })
1017
+ ] })
1018
+ ] });
1019
+ }
1020
+ const Ke = /* @__PURE__ */ new Set([
1021
+ "MATCH",
1022
+ "RETURN",
1023
+ "CREATE",
1024
+ "DELETE",
1025
+ "DETACH",
1026
+ "SET",
1027
+ "MERGE",
1028
+ "WHERE",
1029
+ "AND",
1030
+ "OR",
1031
+ "NOT",
1032
+ "IN",
1033
+ "AS",
1034
+ "ORDER",
1035
+ "BY",
1036
+ "ASC",
1037
+ "DESC",
1038
+ "LIMIT",
1039
+ "SKIP",
1040
+ "WITH",
1041
+ "UNWIND",
1042
+ "OPTIONAL",
1043
+ "CALL",
1044
+ "YIELD",
1045
+ "SHOW",
1046
+ "TAGS",
1047
+ "EDGES",
1048
+ "INDEXES",
1049
+ "EXPLAIN",
1050
+ "PROFILE",
1051
+ "DISTINCT",
1052
+ "COUNT",
1053
+ "SUM",
1054
+ "AVG",
1055
+ "MIN",
1056
+ "MAX",
1057
+ "COLLECT",
1058
+ "LENGTH",
1059
+ "SIZE",
1060
+ "TO_INT",
1061
+ "TO_FLOAT",
1062
+ "ToString",
1063
+ "HAS",
1064
+ "STARTS",
1065
+ "ENDS",
1066
+ "CONTAINS",
1067
+ "IS",
1068
+ "NULL",
1069
+ "TRUE",
1070
+ "FALSE",
1071
+ "CASE",
1072
+ "WHEN",
1073
+ "THEN",
1074
+ "ELSE",
1075
+ "END",
1076
+ "FOREACH",
1077
+ "REMOVE",
1078
+ "ADD",
1079
+ "DROP",
1080
+ "REBUILD",
1081
+ "ALTER",
1082
+ "IF",
1083
+ "NOT",
1084
+ "EXISTS"
1085
+ ]), me = /* @__PURE__ */ new Set([
1086
+ "db.version",
1087
+ "db.branches",
1088
+ "db.commits",
1089
+ "db.head",
1090
+ "db.stats",
1091
+ "db.tags",
1092
+ "db.edges",
1093
+ "db.indexes"
1094
+ ]), Je = [
1095
+ // 关键字
1096
+ { text: "MATCH", desc: "模式匹配", category: "keyword" },
1097
+ { text: "RETURN", desc: "返回结果", category: "keyword" },
1098
+ { text: "CREATE", desc: "创建节点/边", category: "keyword" },
1099
+ { text: "DELETE", desc: "删除节点/边", category: "keyword" },
1100
+ { text: "DETACH DELETE", desc: "删除节点及关联边", category: "keyword" },
1101
+ { text: "MERGE", desc: "查找或创建", category: "keyword" },
1102
+ { text: "WHERE", desc: "过滤条件", category: "keyword" },
1103
+ { text: "SET", desc: "设置属性", category: "keyword" },
1104
+ { text: "ORDER BY", desc: "排序", category: "keyword" },
1105
+ { text: "LIMIT", desc: "限制数量", category: "keyword" },
1106
+ { text: "SKIP", desc: "跳过记录", category: "keyword" },
1107
+ { text: "WITH", desc: "传递中间结果", category: "keyword" },
1108
+ { text: "OPTIONAL MATCH", desc: "可选匹配", category: "keyword" },
1109
+ { text: "UNWIND", desc: "展开列表", category: "keyword" },
1110
+ { text: "DISTINCT", desc: "去重", category: "keyword" },
1111
+ { text: "AS", desc: "别名", category: "keyword" },
1112
+ { text: "AND", desc: "逻辑与", category: "keyword" },
1113
+ { text: "OR", desc: "逻辑或", category: "keyword" },
1114
+ { text: "NOT", desc: "逻辑非", category: "keyword" },
1115
+ { text: "IS NULL", desc: "判空", category: "keyword" },
1116
+ { text: "IS NOT NULL", desc: "非空判断", category: "keyword" },
1117
+ { text: "EXISTS", desc: "存在性检查", category: "keyword" },
1118
+ { text: "CONTAINS", desc: "包含匹配", category: "keyword" },
1119
+ { text: "STARTS WITH", desc: "前缀匹配", category: "keyword" },
1120
+ { text: "ENDS WITH", desc: "后缀匹配", category: "keyword" },
1121
+ // 内置过程
1122
+ { text: "CALL db.version()", desc: "数据库版本", category: "builtin" },
1123
+ { text: "CALL db.branches()", desc: "分支列表", category: "builtin" },
1124
+ { text: "CALL db.commits()", desc: "提交历史", category: "builtin" },
1125
+ { text: "CALL db.stats()", desc: "统计信息", category: "builtin" },
1126
+ { text: "CALL db.tags()", desc: "标签列表", category: "builtin" },
1127
+ { text: "CALL db.edges()", desc: "边类型列表", category: "builtin" },
1128
+ { text: "CALL db.indexes()", desc: "索引列表", category: "builtin" },
1129
+ { text: "CALL db.head('main')", desc: "当前 head", category: "builtin" },
1130
+ { text: "SHOW TAGS", desc: "显示所有标签", category: "builtin" },
1131
+ { text: "SHOW EDGES", desc: "显示所有边类型", category: "builtin" },
1132
+ { text: "SHOW INDEXES", desc: "显示所有索引", category: "builtin" },
1133
+ // 聚合函数
1134
+ { text: "count(*)", desc: "计数", category: "function" },
1135
+ { text: "count(n)", desc: "节点计数", category: "function" },
1136
+ { text: "sum(n.age)", desc: "求和", category: "function" },
1137
+ { text: "avg(n.age)", desc: "平均值", category: "function" },
1138
+ { text: "min(n.age)", desc: "最小值", category: "function" },
1139
+ { text: "max(n.age)", desc: "最大值", category: "function" },
1140
+ { text: "collect(n.name)", desc: "收集为列表", category: "function" },
1141
+ // 常用模式
1142
+ { text: "MATCH (n) RETURN n LIMIT 10", desc: "查询所有节点", category: "pattern" },
1143
+ { text: "MATCH (n:Person) RETURN n", desc: "按标签查询", category: "pattern" },
1144
+ { text: "MATCH (n:Person {name: 'Alice'}) RETURN n", desc: "按属性查询", category: "pattern" },
1145
+ { text: "MATCH (a)-[r]->(b) RETURN a, r, b LIMIT 10", desc: "查询关系", category: "pattern" },
1146
+ { text: "CREATE (n:Person {name: 'Alice', age: 30})", desc: "创建节点", category: "pattern" },
1147
+ { text: "CREATE (a)-[:KNOWS]->(b)", desc: "创建关系", category: "pattern" },
1148
+ { text: "MERGE (n:Person {name: 'Alice'})", desc: " Upsert 节点", category: "pattern" },
1149
+ // DDL
1150
+ { text: "CREATE TAG Person (name STRING, age INT)", desc: "创建标签", category: "ddl" },
1151
+ { text: "CREATE EDGE KNOWS ()", desc: "创建边类型", category: "ddl" },
1152
+ { text: "CREATE TAG INDEX idx_name ON Person(name)", desc: "创建索引", category: "ddl" }
1153
+ ], pe = {
1154
+ keyword: "#c084fc",
1155
+ builtin: "#67e8f9",
1156
+ function: "#93c5fd",
1157
+ pattern: "#86efac",
1158
+ ddl: "#fbbf24"
1159
+ };
1160
+ function Xe({ value: t, onChange: r, onKeyDown: o, rows: a = 10 }) {
1161
+ const d = te(null), p = te(null), [S, f] = N([]), [x, l] = N(0), [C, j] = N(!1), [v, A] = N({ top: 0, left: 0 }), k = K(() => {
1162
+ d.current && p.current && (d.current.scrollTop = p.current.scrollTop, d.current.scrollLeft = p.current.scrollLeft);
1163
+ }, []);
1164
+ function g(c, b) {
1165
+ const T = c.substring(0, b).match(/[a-zA-Z_*.]+$/);
1166
+ return T ? T[0] : "";
1167
+ }
1168
+ function h(c, b) {
1169
+ const T = c.value.substring(0, b).split(`
1170
+ `), w = T.length - 1, y = T[T.length - 1].length;
1171
+ return {
1172
+ top: (w + 1) * 22 - c.scrollTop + 4,
1173
+ left: Math.min(y * 7.8 + 10, c.clientWidth - 200)
1174
+ };
1175
+ }
1176
+ const n = K((c) => {
1177
+ const b = c.target.value;
1178
+ r(b);
1179
+ const E = c.target.selectionStart, T = g(b, E);
1180
+ if (T.length >= 1) {
1181
+ const w = Je.filter(
1182
+ (y) => y.text.toLowerCase().startsWith(T.toLowerCase()) || y.desc.includes(T)
1183
+ ).slice(0, 12);
1184
+ w.length > 0 ? (f(w), l(0), j(!0), A(h(c.target, E))) : j(!1);
1185
+ } else
1186
+ j(!1);
1187
+ }, [r]), s = K((c) => {
1188
+ if (C && S.length > 0) {
1189
+ if (c.key === "ArrowDown") {
1190
+ c.preventDefault(), l((b) => (b + 1) % S.length);
1191
+ return;
1192
+ }
1193
+ if (c.key === "ArrowUp") {
1194
+ c.preventDefault(), l((b) => (b - 1 + S.length) % S.length);
1195
+ return;
1196
+ }
1197
+ if (c.key === "Tab" || c.key === "Enter") {
1198
+ c.preventDefault(), m(S[x]);
1199
+ return;
1200
+ }
1201
+ if (c.key === "Escape") {
1202
+ j(!1);
1203
+ return;
1204
+ }
1205
+ }
1206
+ o && o(c);
1207
+ }, [C, S, x, o]);
1208
+ function m(c) {
1209
+ const b = p.current;
1210
+ if (!b) return;
1211
+ const E = b.selectionStart, T = b.value, w = g(T, E), y = T.substring(0, E - w.length), L = T.substring(E), R = y + c.text + L;
1212
+ r(R), j(!1), setTimeout(() => {
1213
+ const O = E - w.length + c.text.length;
1214
+ b.setSelectionRange(O, O), b.focus();
1215
+ }, 0);
1216
+ }
1217
+ $(() => {
1218
+ if (!C) return;
1219
+ function c(b) {
1220
+ p.current && !p.current.contains(b.target) && j(!1);
1221
+ }
1222
+ return document.addEventListener("mousedown", c), () => document.removeEventListener("mousedown", c);
1223
+ }, [C]);
1224
+ const i = Ve(t || "");
1225
+ return /* @__PURE__ */ e.jsxs("div", { className: "cypher-editor-wrap", style: { position: "relative" }, children: [
1226
+ /* @__PURE__ */ e.jsx(
1227
+ "pre",
1228
+ {
1229
+ ref: d,
1230
+ className: "cypher-editor-highlight",
1231
+ "aria-hidden": "true",
1232
+ style: {
1233
+ position: "absolute",
1234
+ top: 0,
1235
+ left: 0,
1236
+ right: 0,
1237
+ bottom: 0,
1238
+ margin: 0,
1239
+ padding: "8px 10px",
1240
+ border: "1px solid #334155",
1241
+ borderRadius: 6,
1242
+ background: "#1e293b",
1243
+ color: "#e2e8f0",
1244
+ fontFamily: "'SFMono-Regular', Menlo, Consolas, monospace",
1245
+ fontSize: 13,
1246
+ lineHeight: 1.5,
1247
+ overflow: "auto",
1248
+ whiteSpace: "pre-wrap",
1249
+ wordBreak: "break-all",
1250
+ pointerEvents: "none",
1251
+ zIndex: 1
1252
+ },
1253
+ dangerouslySetInnerHTML: { __html: i }
1254
+ }
1255
+ ),
1256
+ /* @__PURE__ */ e.jsx(
1257
+ "textarea",
1258
+ {
1259
+ ref: p,
1260
+ value: t,
1261
+ onChange: n,
1262
+ onScroll: k,
1263
+ onKeyDown: s,
1264
+ spellCheck: !1,
1265
+ rows: a,
1266
+ placeholder: "MATCH (n:Person) RETURN n LIMIT 10",
1267
+ style: {
1268
+ width: "100%",
1269
+ marginTop: 12,
1270
+ background: "transparent",
1271
+ color: "transparent",
1272
+ caretColor: "#e2e8f0",
1273
+ border: "1px solid #334155",
1274
+ borderRadius: 6,
1275
+ padding: "8px 10px",
1276
+ fontFamily: "'SFMono-Regular', Menlo, Consolas, monospace",
1277
+ fontSize: 13,
1278
+ lineHeight: 1.5,
1279
+ resize: "vertical",
1280
+ position: "relative",
1281
+ zIndex: 2
1282
+ }
1283
+ }
1284
+ ),
1285
+ C && S.length > 0 && /* @__PURE__ */ e.jsxs(
1286
+ "div",
1287
+ {
1288
+ className: "cypher-autocomplete",
1289
+ style: {
1290
+ position: "absolute",
1291
+ top: v.top,
1292
+ left: v.left,
1293
+ zIndex: 100,
1294
+ background: "#1e293b",
1295
+ border: "1px solid #334155",
1296
+ borderRadius: 6,
1297
+ boxShadow: "0 8px 24px rgba(0,0,0,0.4)",
1298
+ maxHeight: 240,
1299
+ overflowY: "auto",
1300
+ minWidth: 260
1301
+ },
1302
+ children: [
1303
+ S.map((c, b) => /* @__PURE__ */ e.jsxs(
1304
+ "div",
1305
+ {
1306
+ className: `autocomplete-item ${b === x ? "selected" : ""}`,
1307
+ style: {
1308
+ padding: "6px 10px",
1309
+ cursor: "pointer",
1310
+ display: "flex",
1311
+ alignItems: "center",
1312
+ gap: 8,
1313
+ background: b === x ? "#334155" : "transparent",
1314
+ borderBottom: b < S.length - 1 ? "1px solid #1e293b" : "none"
1315
+ },
1316
+ onMouseEnter: () => l(b),
1317
+ onMouseDown: (E) => {
1318
+ E.preventDefault(), m(c);
1319
+ },
1320
+ children: [
1321
+ /* @__PURE__ */ e.jsx("span", { style: {
1322
+ fontSize: 10,
1323
+ fontWeight: 600,
1324
+ padding: "1px 4px",
1325
+ borderRadius: 3,
1326
+ background: pe[c.category] + "20",
1327
+ color: pe[c.category],
1328
+ minWidth: 48,
1329
+ textAlign: "center"
1330
+ }, children: c.category }),
1331
+ /* @__PURE__ */ e.jsx("span", { className: "mono", style: { fontSize: 12, color: "#e2e8f0", flex: 1 }, children: c.text }),
1332
+ /* @__PURE__ */ e.jsx("span", { style: { fontSize: 11, color: "#64748b", whiteSpace: "nowrap" }, children: c.desc })
1333
+ ]
1334
+ },
1335
+ b
1336
+ )),
1337
+ /* @__PURE__ */ e.jsx("div", { style: { padding: "4px 10px", fontSize: 10, color: "#475569", borderTop: "1px solid #334155" }, children: "Tab/Enter 选择 · ↑↓ 导航 · Esc 关闭" })
1338
+ ]
1339
+ }
1340
+ )
1341
+ ] });
1342
+ }
1343
+ function Ve(t) {
1344
+ const r = [];
1345
+ let o = 0;
1346
+ for (; o < t.length; ) {
1347
+ if (t[o] === "-" && t[o + 1] === "-") {
1348
+ const a = t.indexOf(`
1349
+ `, o), d = a === -1 ? t.substring(o) : t.substring(o, a);
1350
+ r.push(`<span class="hl-comment">${U(d)}</span>`), o = a === -1 ? t.length : a;
1351
+ continue;
1352
+ }
1353
+ if (t[o] === "'") {
1354
+ let a = o + 1;
1355
+ for (; a < t.length && t[a] !== "'"; )
1356
+ t[a] === "\\" && a++, a++;
1357
+ a = Math.min(a + 1, t.length), r.push(`<span class="hl-string">${U(t.substring(o, a))}</span>`), o = a;
1358
+ continue;
1359
+ }
1360
+ if (t[o] === '"') {
1361
+ let a = o + 1;
1362
+ for (; a < t.length && t[a] !== '"'; )
1363
+ t[a] === "\\" && a++, a++;
1364
+ a = Math.min(a + 1, t.length), r.push(`<span class="hl-string">${U(t.substring(o, a))}</span>`), o = a;
1365
+ continue;
1366
+ }
1367
+ if (/[0-9]/.test(t[o]) && (o === 0 || /[\s,({\-:[=<>!]/.test(t[o - 1]))) {
1368
+ let a = o;
1369
+ for (; a < t.length && /[0-9.]/.test(t[a]); ) a++;
1370
+ r.push(`<span class="hl-number">${U(t.substring(o, a))}</span>`), o = a;
1371
+ continue;
1372
+ }
1373
+ if (/[a-zA-Z_]/.test(t[o])) {
1374
+ let a = o;
1375
+ for (; a < t.length && /[a-zA-Z0-9_]/.test(t[a]); ) a++;
1376
+ const d = t.substring(o, a), p = d.toUpperCase();
1377
+ Ke.has(p) ? r.push(`<span class="hl-keyword">${U(d)}</span>`) : me.has(p) || me.has(d.toLowerCase()) ? r.push(`<span class="hl-builtin">${U(d)}</span>`) : a < t.length && t[a] === "(" ? r.push(`<span class="hl-function">${U(d)}</span>`) : p === "ASC" || p === "DESC" ? r.push(`<span class="hl-keyword">${U(d)}</span>`) : r.push(U(d)), o = a;
1378
+ continue;
1379
+ }
1380
+ if ("-><-[]{}(),:.;=<>!+".includes(t[o])) {
1381
+ r.push(`<span class="hl-op">${U(t[o])}</span>`), o++;
1382
+ continue;
1383
+ }
1384
+ r.push(U(t[o])), o++;
1385
+ }
1386
+ return r.join("");
1387
+ }
1388
+ function U(t) {
1389
+ return t === "&" ? "&amp;" : t === "<" ? "&lt;" : t === ">" ? "&gt;" : t === '"' ? "&quot;" : t;
1390
+ }
1391
+ const ne = {
1392
+ 节点与边: `CREATE (a:Person {name: 'Alice', age: 30}),
1393
+ (b:Person {name: 'Bob', age: 25}),
1394
+ (c:Person {name: 'Carol', age: 28}),
1395
+ (a)-[:KNOWS]->(b),
1396
+ (b)-[:KNOWS]->(c)`,
1397
+ "查询所有 Person": "MATCH (n:Person) RETURN n.name AS name, n.age AS age ORDER BY n.age DESC",
1398
+ 变长路径: "MATCH (a:Person {name: 'Alice'})-[:KNOWS*1..3]->(b:Person) RETURN b.name AS friend",
1399
+ 反向关系: "MATCH (b:Person)<-[:KNOWS]-(a:Person) RETURN a.name AS friendOf, b.name AS who",
1400
+ 聚合分组: "MATCH (n:Person) RETURN n.age AS age, count(n) AS total ORDER BY age",
1401
+ "CALL db.version": "CALL db.version()",
1402
+ "CALL db.branches": "CALL db.branches()",
1403
+ "CALL db.commits": "CALL db.commits() LIMIT 10",
1404
+ "CALL db.head": "CALL db.head('main')",
1405
+ "SHOW TAGS": "SHOW TAGS",
1406
+ "SHOW EDGES": "SHOW EDGES",
1407
+ "SHOW STATS": "CALL db.stats()",
1408
+ EXPLAIN: "EXPLAIN MATCH (n:Person) WHERE n.age > 20 RETURN n"
1409
+ };
1410
+ function Ye({ server: t }) {
1411
+ const [r, o] = N(ne.节点与边), [a, d] = N("main"), [p, S] = N(""), [f, x] = N([]), [l, C] = N([]), [j, v] = N("branch"), [A, k] = N(!1), [g, h] = N(null), [n, s] = N(null), [m, i] = N(null), [c, b] = N(() => {
1412
+ try {
1413
+ return JSON.parse(localStorage.getItem("z-graph-history") || "[]");
1414
+ } catch {
1415
+ return [];
1416
+ }
1417
+ }), [E, T] = N(!1);
1418
+ $(() => {
1419
+ let u = !1;
1420
+ async function P() {
1421
+ try {
1422
+ const [I, M] = await Promise.all([W.branches(), W.commits()]), H = Array.isArray(I) ? I : I && I.Name ? [I.Name] : [], q = Array.isArray(M) ? M : [];
1423
+ x(H), C(q), H.length && !H.find((se) => se === a) && d(H[0]);
1424
+ } catch {
1425
+ }
1426
+ }
1427
+ P();
1428
+ }, [t.head]);
1429
+ function w(u, P) {
1430
+ const I = { cypher: u.substring(0, 200), time: Date.now(), elapsed: P, branch: a }, M = [I, ...c.filter((H) => H.cypher !== I.cypher)].slice(0, 50);
1431
+ b(M);
1432
+ try {
1433
+ localStorage.setItem("z-graph-history", JSON.stringify(M));
1434
+ } catch {
1435
+ }
1436
+ }
1437
+ const y = K(async () => {
1438
+ if (!r.trim()) return;
1439
+ k(!0), s(null), h(null), i(null);
1440
+ const u = performance.now();
1441
+ try {
1442
+ const P = await W.query(
1443
+ r,
1444
+ j === "branch" ? a : null,
1445
+ j === "commit" ? p : null
1446
+ ), I = Math.round(performance.now() - u) + "ms";
1447
+ h(P), i(I), w(r, I);
1448
+ } catch (P) {
1449
+ s(P.message), w(r, "error");
1450
+ } finally {
1451
+ k(!1);
1452
+ }
1453
+ }, [r, a, p, j]);
1454
+ function L(u) {
1455
+ o(ne[u]);
1456
+ }
1457
+ function R(u) {
1458
+ o(u.cypher), u.branch && d(u.branch), T(!1);
1459
+ }
1460
+ function O(u) {
1461
+ if (u == null) return /* @__PURE__ */ e.jsx("div", { className: "empty", children: "无返回" });
1462
+ if (typeof u == "string") return /* @__PURE__ */ e.jsx("pre", { children: u });
1463
+ if (Array.isArray(u)) {
1464
+ if (u.length === 0) return /* @__PURE__ */ e.jsx("div", { className: "empty", children: "0 行结果" });
1465
+ const P = Array.from(u.reduce((I, M) => (M && typeof M == "object" && Object.keys(M).forEach((H) => I.add(H)), I), /* @__PURE__ */ new Set()));
1466
+ return /* @__PURE__ */ e.jsxs("table", { children: [
1467
+ /* @__PURE__ */ e.jsx("thead", { children: /* @__PURE__ */ e.jsx("tr", { children: P.map((I) => /* @__PURE__ */ e.jsx("th", { children: I }, I)) }) }),
1468
+ /* @__PURE__ */ e.jsx("tbody", { children: u.map((I, M) => /* @__PURE__ */ e.jsx("tr", { children: P.map((H) => /* @__PURE__ */ e.jsx("td", { className: "mono", children: Ze(I[H]) }, H)) }, M)) })
1469
+ ] });
1470
+ }
1471
+ return /* @__PURE__ */ e.jsx("pre", { children: JSON.stringify(u, null, 2) });
1472
+ }
1473
+ function z() {
1474
+ if (!g || !Array.isArray(g) || g.length === 0) return;
1475
+ const u = Array.from(g.reduce((I, M) => (M && typeof M == "object" && Object.keys(M).forEach((H) => I.add(H)), I), /* @__PURE__ */ new Set())), P = [u.join(",")];
1476
+ for (const I of g)
1477
+ P.push(u.map((M) => {
1478
+ const H = I[M];
1479
+ if (H == null) return "";
1480
+ const q = typeof H == "object" ? JSON.stringify(H) : String(H);
1481
+ return q.includes(",") || q.includes('"') || q.includes(`
1482
+ `) ? '"' + q.replace(/"/g, '""') + '"' : q;
1483
+ }).join(","));
1484
+ G(P.join(`
1485
+ `), "z-graph-query.csv", "text/csv;charset=utf-8");
1486
+ }
1487
+ function D() {
1488
+ if (!g) return;
1489
+ const u = JSON.stringify(g, null, 2);
1490
+ G(u, "z-graph-query.json", "application/json;charset=utf-8");
1491
+ }
1492
+ function G(u, P, I) {
1493
+ const M = new Blob([u], { type: I }), H = URL.createObjectURL(M), q = document.createElement("a");
1494
+ q.href = H, q.download = P, document.body.appendChild(q), q.click(), document.body.removeChild(q), URL.revokeObjectURL(H);
1495
+ }
1496
+ return /* @__PURE__ */ e.jsxs(e.Fragment, { children: [
1497
+ /* @__PURE__ */ e.jsxs("div", { className: "card", children: [
1498
+ /* @__PURE__ */ e.jsxs("div", { className: "toolbar", children: [
1499
+ /* @__PURE__ */ e.jsx("button", { className: "primary", disabled: A || !r.trim(), onClick: y, children: A ? "执行中…" : "执行" }),
1500
+ /* @__PURE__ */ e.jsx("button", { onClick: () => o(""), disabled: A, children: "清空" }),
1501
+ /* @__PURE__ */ e.jsxs("select", { onChange: (u) => L(u.target.value), value: "", children: [
1502
+ /* @__PURE__ */ e.jsx("option", { value: "", disabled: !0, children: "载入示例…" }),
1503
+ Object.keys(ne).map((u) => /* @__PURE__ */ e.jsx("option", { value: u, children: u }, u))
1504
+ ] }),
1505
+ /* @__PURE__ */ e.jsxs("button", { onClick: () => T(!E), disabled: A, children: [
1506
+ "历史 (",
1507
+ c.length,
1508
+ ")"
1509
+ ] }),
1510
+ /* @__PURE__ */ e.jsx("span", { style: { flex: 1 } }),
1511
+ /* @__PURE__ */ e.jsxs("div", { className: "tabs", style: { margin: 0, borderBottom: "none" }, children: [
1512
+ /* @__PURE__ */ e.jsx("button", { className: j === "branch" ? "active" : "", onClick: () => v("branch"), children: "分支 head" }),
1513
+ /* @__PURE__ */ e.jsx("button", { className: j === "commit" ? "active" : "", onClick: () => v("commit"), children: "指定 commit" })
1514
+ ] })
1515
+ ] }),
1516
+ E && /* @__PURE__ */ e.jsxs("div", { className: "history-panel", children: [
1517
+ c.length === 0 && /* @__PURE__ */ e.jsx("div", { className: "muted", children: "暂无历史" }),
1518
+ c.slice(0, 20).map((u, P) => /* @__PURE__ */ e.jsxs("div", { className: "history-item", onClick: () => R(u), children: [
1519
+ /* @__PURE__ */ e.jsxs("span", { className: "history-cypher mono", children: [
1520
+ u.cypher.substring(0, 80),
1521
+ u.cypher.length > 80 ? "…" : ""
1522
+ ] }),
1523
+ /* @__PURE__ */ e.jsxs("span", { className: "history-meta", children: [
1524
+ u.elapsed && /* @__PURE__ */ e.jsx("span", { className: "tag ok", children: u.elapsed }),
1525
+ /* @__PURE__ */ e.jsx("span", { className: "muted", children: new Date(u.time).toLocaleTimeString() })
1526
+ ] })
1527
+ ] }, P))
1528
+ ] }),
1529
+ /* @__PURE__ */ e.jsx("div", { style: { marginTop: 12 }, children: j === "branch" ? /* @__PURE__ */ e.jsx("select", { value: a, onChange: (u) => d(u.target.value), children: f.map((u) => /* @__PURE__ */ e.jsx("option", { value: u, children: u }, u)) }) : /* @__PURE__ */ e.jsxs("select", { value: p, onChange: (u) => S(u.target.value), children: [
1530
+ /* @__PURE__ */ e.jsx("option", { value: "", children: "选择一个 commit" }),
1531
+ l.slice().reverse().map((u) => /* @__PURE__ */ e.jsxs("option", { value: u.id, children: [
1532
+ u.id.substring(0, 12),
1533
+ " · ",
1534
+ u.branch,
1535
+ " · ",
1536
+ u.message
1537
+ ] }, u.id))
1538
+ ] }) }),
1539
+ /* @__PURE__ */ e.jsx(
1540
+ Xe,
1541
+ {
1542
+ value: r,
1543
+ onChange: o,
1544
+ onKeyDown: (u) => {
1545
+ (u.ctrlKey || u.metaKey) && u.key === "Enter" && (u.preventDefault(), y());
1546
+ },
1547
+ rows: 10
1548
+ }
1549
+ ),
1550
+ /* @__PURE__ */ e.jsx("div", { className: "help", children: "支持 ; 分隔多语句; Ctrl+Enter 快捷执行;写查询在 main 上产生新 commit。" })
1551
+ ] }),
1552
+ /* @__PURE__ */ e.jsxs("div", { className: "card", children: [
1553
+ /* @__PURE__ */ e.jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center" }, children: [
1554
+ /* @__PURE__ */ e.jsxs("h2", { style: { margin: 0 }, children: [
1555
+ "结果",
1556
+ m && /* @__PURE__ */ e.jsx("span", { className: "tag ok", style: { marginLeft: 8, fontSize: 11 }, children: m }),
1557
+ g && Array.isArray(g) && /* @__PURE__ */ e.jsxs("span", { className: "muted", style: { marginLeft: 8, fontSize: 13 }, children: [
1558
+ g.length,
1559
+ " 行"
1560
+ ] })
1561
+ ] }),
1562
+ g && Array.isArray(g) && g.length > 0 && /* @__PURE__ */ e.jsxs("div", { className: "toolbar", children: [
1563
+ /* @__PURE__ */ e.jsx("button", { onClick: z, children: "📥 CSV" }),
1564
+ /* @__PURE__ */ e.jsx("button", { onClick: D, children: "📥 JSON" })
1565
+ ] })
1566
+ ] }),
1567
+ n && /* @__PURE__ */ e.jsx("div", { className: "results", children: /* @__PURE__ */ e.jsx("pre", { className: "error", children: n }) }),
1568
+ !n && !g && /* @__PURE__ */ e.jsx("div", { className: "empty", children: "尚未执行" }),
1569
+ !n && g && /* @__PURE__ */ e.jsx("div", { className: "results", children: O(g) })
1570
+ ] })
1571
+ ] });
1572
+ }
1573
+ function Ze(t) {
1574
+ return t == null ? "" : typeof t == "object" ? JSON.stringify(t) : String(t);
1575
+ }
1576
+ const ue = [
1577
+ { label: "创建 TAG", cypher: "CREATE TAG IF NOT EXISTS Person (name string, age int)", category: "DDL" },
1578
+ { label: "创建 TAG (Company)", cypher: "CREATE TAG IF NOT EXISTS Company (name string, founded int)", category: "DDL" },
1579
+ { label: "创建 EDGE", cypher: "CREATE EDGE IF NOT EXISTS KNOWS (since int)", category: "DDL" },
1580
+ { label: "创建 EDGE (WORKS_AT)", cypher: "CREATE EDGE IF NOT EXISTS WORKS_AT (role string)", category: "DDL" },
1581
+ { label: "创建索引", cypher: "CREATE TAG INDEX IF NOT EXISTS idx_person_name ON Person(name)", category: "DDL" },
1582
+ { label: "添加属性", cypher: "ALTER TAG Person ADD (email string)", category: "DDL" },
1583
+ { label: "创建节点", cypher: "CREATE (n:Person {name: 'Alice', age: 30})", category: "写入" },
1584
+ { label: "批量创建", cypher: `CREATE (a:Person {name: 'Alice', age: 30}),
1585
+ (b:Person {name: 'Bob', age: 25}),
1586
+ (a)-[:KNOWS {since: 2020}]->(b)`, category: "写入" },
1587
+ { label: "查询所有节点", cypher: "MATCH (n) RETURN labels(n) AS labels, n.name AS name LIMIT 50", category: "查询" },
1588
+ { label: "变长路径", cypher: `MATCH (a:Person)-[:KNOWS*1..3]->(b:Person)
1589
+ RETURN a.name AS from, b.name AS to LIMIT 100`, category: "查询" },
1590
+ { label: "聚合统计", cypher: `MATCH (n:Person)
1591
+ RETURN n.age AS age, count(n) AS count ORDER BY age`, category: "查询" },
1592
+ { label: "OPTIONAL MATCH", cypher: `MATCH (a:Person)-[r?:KNOWS]->(b:Person)
1593
+ RETURN a.name AS from, b.name AS to`, category: "查询" }
1594
+ ];
1595
+ function Qe({ server: t }) {
1596
+ const [r, o] = N("TAGS"), [a, d] = N([]), [p, S] = N(!1), [f, x] = N(null), [l, C] = N(null), [j, v] = N(null), [A, k] = N(!1), g = K(async () => {
1597
+ S(!0), x(null);
1598
+ try {
1599
+ const s = await W.query(xe(r), "main", null);
1600
+ d(Array.isArray(s) ? s : []);
1601
+ } catch (s) {
1602
+ x(s.message), d([]);
1603
+ } finally {
1604
+ S(!1);
1605
+ }
1606
+ }, [r]);
1607
+ $(() => {
1608
+ g();
1609
+ }, [r, t.head]);
1610
+ async function h(s) {
1611
+ k(!0), v(null), C(null);
1612
+ try {
1613
+ const m = await W.query(s);
1614
+ C(m), setTimeout(g, 500);
1615
+ } catch (m) {
1616
+ v(m.message);
1617
+ } finally {
1618
+ k(!1);
1619
+ }
1620
+ }
1621
+ const n = [...new Set(ue.map((s) => s.category))];
1622
+ return /* @__PURE__ */ e.jsxs(e.Fragment, { children: [
1623
+ /* @__PURE__ */ e.jsxs("div", { className: "card", children: [
1624
+ /* @__PURE__ */ e.jsx("h2", { children: "DDL 快捷操作" }),
1625
+ /* @__PURE__ */ e.jsx("div", { className: "muted", style: { marginBottom: 12 }, children: "点击按钮直接执行 DDL 语句,写入操作会在 main 分支产生新 commit。" }),
1626
+ n.map((s) => /* @__PURE__ */ e.jsxs("div", { children: [
1627
+ /* @__PURE__ */ e.jsx("h3", { style: { marginTop: 12, marginBottom: 6 }, children: s }),
1628
+ /* @__PURE__ */ e.jsx("div", { className: "chip-list", children: ue.filter((m) => m.category === s).map((m, i) => /* @__PURE__ */ e.jsx("button", { className: "chip ddl-chip", onClick: () => h(m.cypher), disabled: A, children: m.label }, i)) })
1629
+ ] }, s)),
1630
+ A && /* @__PURE__ */ e.jsx("div", { className: "muted", style: { marginTop: 8 }, children: "执行中…" }),
1631
+ j && /* @__PURE__ */ e.jsx("pre", { className: "error", style: { marginTop: 8 }, children: j }),
1632
+ l && /* @__PURE__ */ e.jsx("pre", { className: "results", style: { marginTop: 8 }, children: JSON.stringify(l, null, 2) })
1633
+ ] }),
1634
+ /* @__PURE__ */ e.jsxs("div", { className: "card", children: [
1635
+ /* @__PURE__ */ e.jsxs("div", { className: "toolbar", children: [
1636
+ ["TAGS", "EDGES", "INDEXES"].map((s) => /* @__PURE__ */ e.jsxs(
1637
+ "button",
1638
+ {
1639
+ className: r === s ? "primary" : "",
1640
+ onClick: () => o(s),
1641
+ children: [
1642
+ "SHOW ",
1643
+ s
1644
+ ]
1645
+ },
1646
+ s
1647
+ )),
1648
+ /* @__PURE__ */ e.jsx("button", { onClick: g, disabled: p, children: p ? "刷新中…" : "刷新" })
1649
+ ] }),
1650
+ /* @__PURE__ */ e.jsxs("div", { className: "muted", style: { marginTop: 8 }, children: [
1651
+ "执行:",
1652
+ xe(r)
1653
+ ] })
1654
+ ] }),
1655
+ /* @__PURE__ */ e.jsxs("div", { className: "card", children: [
1656
+ f && /* @__PURE__ */ e.jsx("div", { className: "error", children: f }),
1657
+ !f && a.length === 0 && /* @__PURE__ */ e.jsxs("div", { className: "empty", children: [
1658
+ "尚无 ",
1659
+ r.toLowerCase()
1660
+ ] }),
1661
+ !f && a.length > 0 && /* @__PURE__ */ e.jsx(et, { rows: a })
1662
+ ] })
1663
+ ] });
1664
+ }
1665
+ function xe(t) {
1666
+ return t === "TAGS" ? "SHOW TAGS" : t === "EDGES" ? "SHOW EDGES" : "SHOW INDEXES";
1667
+ }
1668
+ function et({ rows: t }) {
1669
+ const r = Array.from(t.reduce((o, a) => (Object.keys(a || {}).forEach((d) => o.add(d)), o), /* @__PURE__ */ new Set()));
1670
+ return /* @__PURE__ */ e.jsxs("table", { children: [
1671
+ /* @__PURE__ */ e.jsx("thead", { children: /* @__PURE__ */ e.jsx("tr", { children: r.map((o) => /* @__PURE__ */ e.jsx("th", { children: o }, o)) }) }),
1672
+ /* @__PURE__ */ e.jsx("tbody", { children: t.map((o, a) => /* @__PURE__ */ e.jsx("tr", { children: r.map((d) => /* @__PURE__ */ e.jsx("td", { className: "mono", children: tt(o[d]) }, d)) }, a)) })
1673
+ ] });
1674
+ }
1675
+ function tt(t) {
1676
+ return t == null ? "" : typeof t == "object" ? JSON.stringify(t) : String(t);
1677
+ }
1678
+ const st = {
1679
+ GET: "#86efac",
1680
+ POST: "#93c5fd",
1681
+ OPTIONS: "#94a3b8"
1682
+ };
1683
+ function nt() {
1684
+ var g, h;
1685
+ const [t, r] = N(null), [o, a] = N(!0), [d, p] = N(null), [S, f] = N(!0), [x, l] = N({ method: "", status: "", path: "", requestId: "" }), [C, j] = N(null), v = K(async () => {
1686
+ try {
1687
+ const n = {};
1688
+ x.method && (n.method = x.method), x.status && (n.status = x.status), x.path && (n.path = x.path), x.requestId && (n.requestId = x.requestId), n.limit = 200;
1689
+ const s = await W.logs(n);
1690
+ r(s), p(null);
1691
+ } catch (n) {
1692
+ p(n.message);
1693
+ } finally {
1694
+ a(!1);
1695
+ }
1696
+ }, [x]);
1697
+ $(() => {
1698
+ if (v(), !S) return;
1699
+ const n = setInterval(v, 3e3);
1700
+ return () => clearInterval(n);
1701
+ }, [v, S]);
1702
+ function A(n) {
1703
+ if (!n) return "";
1704
+ const s = new Date(n);
1705
+ return s.toLocaleTimeString("zh-CN", { hour12: !1 }) + "." + String(s.getMilliseconds()).padStart(3, "0");
1706
+ }
1707
+ function k(n) {
1708
+ return n >= 500 ? "log-status-error" : n >= 400 ? "log-status-warn" : "log-status-ok";
1709
+ }
1710
+ return /* @__PURE__ */ e.jsxs(e.Fragment, { children: [
1711
+ /* @__PURE__ */ e.jsx("div", { className: "card", children: /* @__PURE__ */ e.jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center" }, children: [
1712
+ /* @__PURE__ */ e.jsxs("div", { children: [
1713
+ /* @__PURE__ */ e.jsx("h2", { children: "请求日志" }),
1714
+ /* @__PURE__ */ e.jsxs("div", { className: "muted", children: [
1715
+ "环形缓冲区最近 ",
1716
+ (t == null ? void 0 : t.bufferSize) || 500,
1717
+ " 条请求记录,自动刷新。"
1718
+ ] })
1719
+ ] }),
1720
+ /* @__PURE__ */ e.jsxs("div", { className: "toolbar", children: [
1721
+ /* @__PURE__ */ e.jsx(
1722
+ "button",
1723
+ {
1724
+ className: S ? "primary" : "",
1725
+ onClick: () => f(!S),
1726
+ children: S ? "⏸ 暂停" : "▶ 自动刷新"
1727
+ }
1728
+ ),
1729
+ /* @__PURE__ */ e.jsx("button", { onClick: v, children: "🔄 刷新" })
1730
+ ] })
1731
+ ] }) }),
1732
+ /* @__PURE__ */ e.jsx("div", { className: "card", children: /* @__PURE__ */ e.jsxs("div", { className: "toolbar", children: [
1733
+ /* @__PURE__ */ e.jsxs("select", { value: x.method, onChange: (n) => l((s) => ({ ...s, method: n.target.value })), children: [
1734
+ /* @__PURE__ */ e.jsx("option", { value: "", children: "全部方法" }),
1735
+ /* @__PURE__ */ e.jsx("option", { value: "GET", children: "GET" }),
1736
+ /* @__PURE__ */ e.jsx("option", { value: "POST", children: "POST" }),
1737
+ /* @__PURE__ */ e.jsx("option", { value: "OPTIONS", children: "OPTIONS" })
1738
+ ] }),
1739
+ /* @__PURE__ */ e.jsxs("select", { value: x.status, onChange: (n) => l((s) => ({ ...s, status: n.target.value })), children: [
1740
+ /* @__PURE__ */ e.jsx("option", { value: "", children: "全部状态" }),
1741
+ /* @__PURE__ */ e.jsx("option", { value: "2xx", children: "2xx 成功" }),
1742
+ /* @__PURE__ */ e.jsx("option", { value: "4xx", children: "4xx 客户端错误" }),
1743
+ /* @__PURE__ */ e.jsx("option", { value: "5xx", children: "5xx 服务器错误" }),
1744
+ /* @__PURE__ */ e.jsx("option", { value: "200", children: "200" }),
1745
+ /* @__PURE__ */ e.jsx("option", { value: "400", children: "400" }),
1746
+ /* @__PURE__ */ e.jsx("option", { value: "401", children: "401" }),
1747
+ /* @__PURE__ */ e.jsx("option", { value: "429", children: "429" }),
1748
+ /* @__PURE__ */ e.jsx("option", { value: "500", children: "500" })
1749
+ ] }),
1750
+ /* @__PURE__ */ e.jsx(
1751
+ "input",
1752
+ {
1753
+ placeholder: "路径过滤…",
1754
+ value: x.path,
1755
+ onChange: (n) => l((s) => ({ ...s, path: n.target.value })),
1756
+ style: { width: 200 }
1757
+ }
1758
+ ),
1759
+ /* @__PURE__ */ e.jsx(
1760
+ "input",
1761
+ {
1762
+ placeholder: "Request ID…",
1763
+ value: x.requestId,
1764
+ onChange: (n) => l((s) => ({ ...s, requestId: n.target.value })),
1765
+ style: { width: 160 }
1766
+ }
1767
+ ),
1768
+ t && /* @__PURE__ */ e.jsxs("span", { style: { fontSize: 12, color: "#64748b" }, children: [
1769
+ "共 ",
1770
+ t.total,
1771
+ " 条记录,显示 ",
1772
+ ((g = t.entries) == null ? void 0 : g.length) || 0,
1773
+ " 条"
1774
+ ] })
1775
+ ] }) }),
1776
+ o && /* @__PURE__ */ e.jsx("div", { className: "card", children: /* @__PURE__ */ e.jsx("div", { className: "empty", children: "加载中…" }) }),
1777
+ d && /* @__PURE__ */ e.jsxs("div", { className: "error-banner", children: [
1778
+ "加载失败: ",
1779
+ d
1780
+ ] }),
1781
+ t && t.entries && /* @__PURE__ */ e.jsx("div", { className: "card", style: { padding: 0, overflow: "hidden" }, children: /* @__PURE__ */ e.jsx("div", { className: "log-table-wrap", children: /* @__PURE__ */ e.jsxs("table", { className: "log-table", children: [
1782
+ /* @__PURE__ */ e.jsx("thead", { children: /* @__PURE__ */ e.jsxs("tr", { children: [
1783
+ /* @__PURE__ */ e.jsx("th", { style: { width: 110 }, children: "时间" }),
1784
+ /* @__PURE__ */ e.jsx("th", { style: { width: 90 }, children: "Request ID" }),
1785
+ /* @__PURE__ */ e.jsx("th", { style: { width: 50 }, children: "方法" }),
1786
+ /* @__PURE__ */ e.jsx("th", { style: { width: 45 }, children: "状态" }),
1787
+ /* @__PURE__ */ e.jsx("th", { children: "路径" }),
1788
+ /* @__PURE__ */ e.jsx("th", { style: { width: 60 }, children: "耗时" }),
1789
+ /* @__PURE__ */ e.jsx("th", { style: { width: 100 }, children: "客户端" })
1790
+ ] }) }),
1791
+ /* @__PURE__ */ e.jsxs("tbody", { children: [
1792
+ t.entries.map((n, s) => /* @__PURE__ */ e.jsxs(
1793
+ "tr",
1794
+ {
1795
+ className: `log-row ${C === s ? "selected" : ""}`,
1796
+ onClick: () => j(C === s ? null : s),
1797
+ children: [
1798
+ /* @__PURE__ */ e.jsx("td", { className: "mono", style: { fontSize: 11, color: "#64748b" }, children: A(n.timestamp) }),
1799
+ /* @__PURE__ */ e.jsx(
1800
+ "td",
1801
+ {
1802
+ className: "mono",
1803
+ style: { fontSize: 10, color: "#64748b", cursor: "pointer" },
1804
+ title: n.requestId,
1805
+ onClick: (m) => {
1806
+ m.stopPropagation(), l((i) => ({ ...i, requestId: n.requestId }));
1807
+ },
1808
+ children: n.requestId ? n.requestId.substring(0, 12) + "…" : "-"
1809
+ }
1810
+ ),
1811
+ /* @__PURE__ */ e.jsx("td", { children: /* @__PURE__ */ e.jsx(
1812
+ "span",
1813
+ {
1814
+ className: "log-method",
1815
+ style: { color: st[n.method] || "#94a3b8" },
1816
+ children: n.method
1817
+ }
1818
+ ) }),
1819
+ /* @__PURE__ */ e.jsx("td", { children: /* @__PURE__ */ e.jsx("span", { className: `log-status ${k(n.status)}`, children: n.status }) }),
1820
+ /* @__PURE__ */ e.jsx("td", { className: "mono", style: { fontSize: 12, color: "#e2e8f0", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }, children: n.path }),
1821
+ /* @__PURE__ */ e.jsxs("td", { className: "mono", style: { fontSize: 12, color: n.elapsedMs > 100 ? "#fbbf24" : "#94a3b8" }, children: [
1822
+ n.elapsedMs,
1823
+ "ms"
1824
+ ] }),
1825
+ /* @__PURE__ */ e.jsx("td", { className: "mono", style: { fontSize: 11, color: "#64748b" }, children: n.clientIp })
1826
+ ]
1827
+ },
1828
+ s
1829
+ )),
1830
+ t.entries.length === 0 && /* @__PURE__ */ e.jsx("tr", { children: /* @__PURE__ */ e.jsx("td", { colSpan: 7, style: { textAlign: "center", padding: 30, color: "#64748b" }, children: "暂无日志记录" }) })
1831
+ ] })
1832
+ ] }) }) }),
1833
+ C !== null && ((h = t == null ? void 0 : t.entries) == null ? void 0 : h[C]) && /* @__PURE__ */ e.jsxs("div", { className: "card", children: [
1834
+ /* @__PURE__ */ e.jsx("h3", { style: { margin: "0 0 8px", fontSize: 14, color: "#94a3b8" }, children: "请求详情" }),
1835
+ /* @__PURE__ */ e.jsx("pre", { className: "results", style: { fontSize: 12, maxHeight: 200 }, children: JSON.stringify(t.entries[C], null, 2) })
1836
+ ] })
1837
+ ] });
1838
+ }
1839
+ const ge = [
1840
+ {
1841
+ method: "GET",
1842
+ path: "/health",
1843
+ name: "健康检查",
1844
+ desc: "返回服务状态、当前 head、节点数和边数。",
1845
+ params: [],
1846
+ response: "{ status, head, nodeCount, edgeCount }"
1847
+ },
1848
+ {
1849
+ method: "POST",
1850
+ path: "/query",
1851
+ name: "执行 Cypher",
1852
+ desc: "执行单条 Cypher 查询。写查询会在分支上产生新 commit。",
1853
+ params: [
1854
+ { name: "cypher", type: "string", required: !0, example: "MATCH (n) RETURN n LIMIT 10" },
1855
+ { name: "branch", type: "string", required: !1, example: "main" },
1856
+ { name: "commit", type: "string", required: !1, example: "" }
1857
+ ],
1858
+ response: "[{ ... }, ...]"
1859
+ },
1860
+ {
1861
+ method: "POST",
1862
+ path: "/query/batch",
1863
+ name: "批量查询",
1864
+ desc: "一次执行多条 Cypher 语句,返回每条的结果和总耗时。",
1865
+ params: [
1866
+ { name: "statements", type: "array", required: !0, example: '[{"cypher":"MATCH (n) RETURN n"}]' }
1867
+ ],
1868
+ response: "{ results: [...], elapsedMs: 123 }"
1869
+ },
1870
+ {
1871
+ method: "POST",
1872
+ path: "/query/explain",
1873
+ name: "查询计划",
1874
+ desc: "返回查询的执行计划(不实际执行写操作),包括操作步骤和复杂度估算。",
1875
+ params: [
1876
+ { name: "cypher", type: "string", required: !0, example: "MATCH (n:Person) WHERE n.age > 20 RETURN n" },
1877
+ { name: "branch", type: "string", required: !1, example: "main" }
1878
+ ],
1879
+ response: "{ plan: { queryType, steps, estimatedComplexity }, cypher, branch }"
1880
+ },
1881
+ {
1882
+ method: "GET",
1883
+ path: "/meta/branches",
1884
+ name: "分支列表",
1885
+ desc: "返回所有分支的名称和当前 head。",
1886
+ params: [],
1887
+ response: '[{ Name: "main", Head: "..." }]'
1888
+ },
1889
+ {
1890
+ method: "GET",
1891
+ path: "/meta/commits",
1892
+ name: "提交历史",
1893
+ desc: "返回所有 commit 的完整历史。",
1894
+ params: [],
1895
+ response: "[{ id, parents, branch, author, message, timestamp, nodeCount, edgeCount }]"
1896
+ },
1897
+ {
1898
+ method: "GET",
1899
+ path: "/meta/schema",
1900
+ name: "Schema 信息",
1901
+ desc: "返回当前分支的 TAG、EDGE 和 INDEX 定义。",
1902
+ params: [
1903
+ { name: "branch", type: "string", required: !1, example: "main" }
1904
+ ],
1905
+ response: "{ branch, tags, edges, indexes }"
1906
+ },
1907
+ {
1908
+ method: "GET",
1909
+ path: "/meta/stats",
1910
+ name: "统计摘要",
1911
+ desc: "返回节点数、边数和 db.stats() 信息。",
1912
+ params: [
1913
+ { name: "branch", type: "string", required: !1, example: "main" }
1914
+ ],
1915
+ response: "{ branch, head, nodeCount, edgeCount, stats }"
1916
+ },
1917
+ {
1918
+ method: "GET",
1919
+ path: "/meta/metrics",
1920
+ name: "运行指标",
1921
+ desc: "返回服务运行指标:请求数、错误率、JVM 内存、运行时间等。",
1922
+ params: [],
1923
+ response: "{ uptimeMs, totalRequests, errorResponses, errorRate, jvmMemory, ... }"
1924
+ },
1925
+ {
1926
+ method: "GET",
1927
+ path: "/meta/logs",
1928
+ name: "请求日志",
1929
+ desc: "返回最近的请求日志(环形缓冲区,最多 500 条),支持过滤。",
1930
+ params: [
1931
+ { name: "limit", type: "number", required: !1, example: "100" },
1932
+ { name: "offset", type: "number", required: !1, example: "0" },
1933
+ { name: "method", type: "string", required: !1, example: "GET" },
1934
+ { name: "status", type: "string", required: !1, example: "4xx" },
1935
+ { name: "path", type: "string", required: !1, example: "/query" }
1936
+ ],
1937
+ response: "{ total, bufferSize, offset, limit, entries: [{ timestamp, method, path, status, elapsedMs, clientIp }] }"
1938
+ },
1939
+ {
1940
+ method: "GET",
1941
+ path: "/meta/export",
1942
+ name: "导出图数据",
1943
+ desc: "导出当前分支的完整图数据(节点 + 边 + schema)。",
1944
+ params: [
1945
+ { name: "branch", type: "string", required: !1, example: "main" }
1946
+ ],
1947
+ response: "{ version, branch, head, schema, nodes, edges, exportedAt }"
1948
+ },
1949
+ {
1950
+ method: "POST",
1951
+ path: "/meta/import",
1952
+ name: "导入节点",
1953
+ desc: "通过 JSON 数组导入节点数据。",
1954
+ params: [
1955
+ { name: "nodes", type: "array", required: !0, example: '[{"label":"Person","name":"Alice","age":30}]' },
1956
+ { name: "branch", type: "string", required: !1, example: "main" }
1957
+ ],
1958
+ response: "{ imported, branch, elapsedMs }"
1959
+ }
1960
+ ];
1961
+ function rt() {
1962
+ const [t, r] = N(null), [o, a] = N(null), [d, p] = N(!1), [S, f] = N(null);
1963
+ async function x(l) {
1964
+ p(!0), a(null), f(null);
1965
+ try {
1966
+ let C;
1967
+ if (l.method === "GET")
1968
+ C = await fe(`http://${ye()}${l.path}`);
1969
+ else {
1970
+ const j = {};
1971
+ for (const v of l.params)
1972
+ v.example && (j[v.name] = v.example);
1973
+ C = await fe(`http://${ye()}${l.path}`, {
1974
+ method: "POST",
1975
+ headers: { "Content-Type": "application/json" },
1976
+ body: JSON.stringify(j)
1977
+ });
1978
+ }
1979
+ a(C);
1980
+ } catch (C) {
1981
+ f(C.message);
1982
+ } finally {
1983
+ p(!1);
1984
+ }
1985
+ }
1986
+ return /* @__PURE__ */ e.jsxs(e.Fragment, { children: [
1987
+ /* @__PURE__ */ e.jsxs("div", { className: "card", children: [
1988
+ /* @__PURE__ */ e.jsx("h2", { children: "API 文档" }),
1989
+ /* @__PURE__ */ e.jsxs("div", { className: "muted", children: [
1990
+ "z-graph HTTP 控制面共 ",
1991
+ ge.length,
1992
+ " 个端点。点击端点展开详情并可交互测试。"
1993
+ ] })
1994
+ ] }),
1995
+ ge.map((l, C) => /* @__PURE__ */ e.jsxs("div", { className: "card api-endpoint-card", children: [
1996
+ /* @__PURE__ */ e.jsxs("div", { className: "api-endpoint-header", onClick: () => r(t === C ? null : C), children: [
1997
+ /* @__PURE__ */ e.jsx("span", { className: `api-method ${l.method.toLowerCase()}`, children: l.method }),
1998
+ /* @__PURE__ */ e.jsx("code", { className: "api-path", children: l.path }),
1999
+ /* @__PURE__ */ e.jsx("span", { className: "api-name", children: l.name }),
2000
+ /* @__PURE__ */ e.jsx("span", { style: { flex: 1 } }),
2001
+ /* @__PURE__ */ e.jsx("span", { className: "api-expand", children: t === C ? "▲" : "▼" })
2002
+ ] }),
2003
+ t === C && /* @__PURE__ */ e.jsxs("div", { className: "api-endpoint-detail", children: [
2004
+ /* @__PURE__ */ e.jsx("p", { children: l.desc }),
2005
+ l.params.length > 0 && /* @__PURE__ */ e.jsxs(e.Fragment, { children: [
2006
+ /* @__PURE__ */ e.jsx("h3", { children: "参数" }),
2007
+ /* @__PURE__ */ e.jsxs("table", { children: [
2008
+ /* @__PURE__ */ e.jsx("thead", { children: /* @__PURE__ */ e.jsxs("tr", { children: [
2009
+ /* @__PURE__ */ e.jsx("th", { children: "名称" }),
2010
+ /* @__PURE__ */ e.jsx("th", { children: "类型" }),
2011
+ /* @__PURE__ */ e.jsx("th", { children: "必填" }),
2012
+ /* @__PURE__ */ e.jsx("th", { children: "示例" })
2013
+ ] }) }),
2014
+ /* @__PURE__ */ e.jsx("tbody", { children: l.params.map((j, v) => /* @__PURE__ */ e.jsxs("tr", { children: [
2015
+ /* @__PURE__ */ e.jsx("td", { className: "mono", children: j.name }),
2016
+ /* @__PURE__ */ e.jsx("td", { children: j.type }),
2017
+ /* @__PURE__ */ e.jsx("td", { children: j.required ? /* @__PURE__ */ e.jsx("span", { className: "tag ok", children: "必填" }) : "可选" }),
2018
+ /* @__PURE__ */ e.jsx("td", { className: "mono", style: { fontSize: 11, color: "#94a3b8" }, children: j.example || "-" })
2019
+ ] }, v)) })
2020
+ ] })
2021
+ ] }),
2022
+ /* @__PURE__ */ e.jsx("h3", { children: "返回值" }),
2023
+ /* @__PURE__ */ e.jsx("pre", { style: { fontSize: 12, color: "#86efac" }, children: l.response }),
2024
+ /* @__PURE__ */ e.jsx("div", { style: { marginTop: 12 }, children: /* @__PURE__ */ e.jsx("button", { className: "primary", onClick: () => x(l), disabled: d, children: d ? "测试中…" : "交互测试" }) }),
2025
+ o && /* @__PURE__ */ e.jsxs("div", { style: { marginTop: 8 }, children: [
2026
+ /* @__PURE__ */ e.jsx("h3", { children: "响应" }),
2027
+ /* @__PURE__ */ e.jsx("pre", { className: "results", style: { fontSize: 11, maxHeight: 300 }, children: typeof o == "string" ? o : JSON.stringify(o, null, 2) })
2028
+ ] }),
2029
+ S && /* @__PURE__ */ e.jsx("div", { className: "error", style: { marginTop: 8 }, children: S })
2030
+ ] })
2031
+ ] }, C))
2032
+ ] });
2033
+ }
2034
+ function ye() {
2035
+ const t = typeof window < "u" && window.__Z_GRAPH_API__ || "/api";
2036
+ return t === "/api" ? window.location.host : t.replace(/^https?:\/\//, "");
2037
+ }
2038
+ async function fe(t, r = {}) {
2039
+ const a = await (await fetch(t, {
2040
+ headers: { Accept: "application/json", ...r.headers || {} },
2041
+ ...r
2042
+ })).text();
2043
+ if (!a) return null;
2044
+ try {
2045
+ return JSON.parse(a);
2046
+ } catch {
2047
+ return a;
2048
+ }
2049
+ }
2050
+ const { Title: at, Paragraph: ot } = Me;
2051
+ function lt() {
2052
+ const t = We(), [r, o] = N(null);
2053
+ $(() => {
2054
+ const d = localStorage.getItem("userInfo");
2055
+ if (d)
2056
+ try {
2057
+ o(JSON.parse(d));
2058
+ } catch {
2059
+ o({ name: d });
2060
+ }
2061
+ }, []);
2062
+ const a = it.filter((d) => d.key !== "/z-graph/home");
2063
+ return /* @__PURE__ */ e.jsxs("div", { children: [
2064
+ /* @__PURE__ */ e.jsx(re, { style: { marginBottom: 16, background: "linear-gradient(135deg, #7c3aed 0%, #6d28d9 100%)", border: "none" }, children: /* @__PURE__ */ e.jsxs(oe, { direction: "vertical", size: 4, style: { color: "#fff" }, children: [
2065
+ /* @__PURE__ */ e.jsxs(at, { level: 3, style: { color: "#fff", margin: 0 }, children: [
2066
+ "欢迎",
2067
+ r != null && r.name ? `,${r.name}` : ""
2068
+ ] }),
2069
+ /* @__PURE__ */ e.jsx(ot, { style: { color: "rgba(255,255,255,0.85)", margin: 0 }, children: "z-graph 图存储控制台 管理台" }),
2070
+ (r == null ? void 0 : r.role) && /* @__PURE__ */ e.jsx(De, { style: { marginTop: 8, background: "rgba(255,255,255,0.2)", color: "#fff", border: "none" }, children: r.role })
2071
+ ] }) }),
2072
+ /* @__PURE__ */ e.jsx(He, { gutter: [16, 16], children: a.map((d) => /* @__PURE__ */ e.jsx(Pe, { xs: 24, sm: 12, md: 12, lg: 8, children: /* @__PURE__ */ e.jsx(re, { hoverable: !0, onClick: () => t(d.key), style: { borderTop: "3px solid #7c3aed" }, children: /* @__PURE__ */ e.jsxs(oe, { align: "start", size: 12, children: [
2073
+ /* @__PURE__ */ e.jsx("div", { style: {
2074
+ width: 44,
2075
+ height: 44,
2076
+ borderRadius: 8,
2077
+ flexShrink: 0,
2078
+ background: "rgba(124,58,237,0.08)",
2079
+ color: "#7c3aed",
2080
+ display: "flex",
2081
+ alignItems: "center",
2082
+ justifyContent: "center",
2083
+ fontSize: 20
2084
+ }, children: d.icon }),
2085
+ /* @__PURE__ */ e.jsxs("div", { style: { minWidth: 0 }, children: [
2086
+ /* @__PURE__ */ e.jsx("div", { style: { fontSize: 15, fontWeight: 600, color: "#0f172a" }, children: d.label }),
2087
+ /* @__PURE__ */ e.jsx("div", { style: { fontSize: 12, color: "#94a3b8", marginTop: 2 }, children: d.key })
2088
+ ] })
2089
+ ] }) }) }, d.key)) })
2090
+ ] });
2091
+ }
2092
+ const J = { username: "admin", password: "123456", user: { name: "admin", role: "管理员" } };
2093
+ function xt() {
2094
+ const [t, r] = N(!1), o = async (a) => {
2095
+ r(!0);
2096
+ try {
2097
+ a.username === J.username && a.password === J.password ? (localStorage.setItem("token", "mock-" + J.username), localStorage.setItem("userInfo", JSON.stringify(J.user)), ie.success("登录成功(mock 模式,待 CTC/SSO 接入)"), window.location.href = "/z-graph/home") : ie.error("用户名或密码错误(默认 admin/123456)");
2098
+ } finally {
2099
+ r(!1);
2100
+ }
2101
+ };
2102
+ return /* @__PURE__ */ e.jsx("div", { style: {
2103
+ height: "100vh",
2104
+ display: "flex",
2105
+ justifyContent: "center",
2106
+ alignItems: "center",
2107
+ background: "linear-gradient(135deg, #eef2ff 0%, #f5f3ff 50%, #eff6ff 100%)"
2108
+ }, children: /* @__PURE__ */ e.jsxs(re, { style: { width: 400, boxShadow: "0 10px 40px rgba(124,58,237,0.12)" }, children: [
2109
+ /* @__PURE__ */ e.jsxs("div", { style: { textAlign: "center", marginBottom: 20 }, children: [
2110
+ /* @__PURE__ */ e.jsx("div", { style: {
2111
+ width: 48,
2112
+ height: 48,
2113
+ borderRadius: 12,
2114
+ margin: "0 auto 12px",
2115
+ background: "linear-gradient(135deg, #7c3aed, #6d28d9)",
2116
+ display: "flex",
2117
+ alignItems: "center",
2118
+ justifyContent: "center",
2119
+ color: "#fff",
2120
+ fontSize: 24,
2121
+ fontWeight: 700
2122
+ }, children: "z" }),
2123
+ /* @__PURE__ */ e.jsx("div", { style: { fontSize: 18, fontWeight: 600, color: "#0f172a" }, children: "z-graph 管理台" })
2124
+ ] }),
2125
+ /* @__PURE__ */ e.jsxs(Z, { onFinish: o, size: "large", children: [
2126
+ /* @__PURE__ */ e.jsx(Z.Item, { name: "username", rules: [{ required: !0, message: "请输入用户名" }], children: /* @__PURE__ */ e.jsx(le, { prefix: /* @__PURE__ */ e.jsx(ve, {}), placeholder: "用户名" }) }),
2127
+ /* @__PURE__ */ e.jsx(Z.Item, { name: "password", rules: [{ required: !0, message: "请输入密码" }], children: /* @__PURE__ */ e.jsx(le.Password, { prefix: /* @__PURE__ */ e.jsx(Te, {}), placeholder: "密码" }) }),
2128
+ /* @__PURE__ */ e.jsx(Z.Item, { style: { marginBottom: 8 }, children: /* @__PURE__ */ e.jsx(
2129
+ ze,
2130
+ {
2131
+ type: "primary",
2132
+ htmlType: "submit",
2133
+ loading: t,
2134
+ block: !0,
2135
+ style: { background: "linear-gradient(135deg, #7c3aed 0%, #6d28d9 100%)", border: "none" },
2136
+ children: "登 录"
2137
+ }
2138
+ ) }),
2139
+ /* @__PURE__ */ e.jsxs("div", { style: { textAlign: "center", color: "#94a3b8", fontSize: 12 }, children: [
2140
+ "Mock 模式:用户名 ",
2141
+ /* @__PURE__ */ e.jsx("b", { children: J.username }),
2142
+ " / 密码 ",
2143
+ /* @__PURE__ */ e.jsx("b", { children: J.password })
2144
+ ] })
2145
+ ] })
2146
+ ] }) });
2147
+ }
2148
+ const gt = { title: "z-graph 图存储控制台", short: "z-graph" }, it = [
2149
+ { key: "/z-graph/home", label: "首页", icon: /* @__PURE__ */ e.jsx(Ee, {}) },
2150
+ { key: "/z-graph/dashboard", label: "总览", icon: /* @__PURE__ */ e.jsx(Ce, {}) },
2151
+ { key: "/z-graph/graph", label: "图视图", icon: /* @__PURE__ */ e.jsx(Ae, {}) },
2152
+ { key: "/z-graph/branches", label: "分支", icon: /* @__PURE__ */ e.jsx(we, {}) },
2153
+ { key: "/z-graph/commits", label: "提交历史", icon: /* @__PURE__ */ e.jsx(ke, {}) },
2154
+ { key: "/z-graph/query", label: "Cypher 查询", icon: /* @__PURE__ */ e.jsx(Ie, {}) },
2155
+ { key: "/z-graph/schema", label: "Schema", icon: /* @__PURE__ */ e.jsx(Le, {}) },
2156
+ { key: "/z-graph/logs", label: "请求日志", icon: /* @__PURE__ */ e.jsx(Re, {}) },
2157
+ { key: "/z-graph/api-docs", label: "API 文档", icon: /* @__PURE__ */ e.jsx(Oe, {}) }
2158
+ ], yt = [
2159
+ { path: "/z-graph/home", Component: lt },
2160
+ // 旧版 console 页面(吃 src/console/styles.css)⇒ 必须走 withGraphConsole,
2161
+ // 否则那份样式表里的裸元素选择器会泄漏到主壳(详见 console/serverHook.jsx 注释)。
2162
+ { path: "/z-graph/dashboard", Component: F(qe) },
2163
+ { path: "/z-graph/graph", Component: F($e) },
2164
+ { path: "/z-graph/branches", Component: F(Be) },
2165
+ { path: "/z-graph/commits", Component: F(Fe) },
2166
+ { path: "/z-graph/query", Component: F(Ye) },
2167
+ { path: "/z-graph/schema", Component: F(Qe) },
2168
+ { path: "/z-graph/logs", Component: F(nt) },
2169
+ { path: "/z-graph/api-docs", Component: F(rt) },
2170
+ // 新版页面(antd 实现)不吃 console 样式表 ⇒ 不加作用域
2171
+ { path: "/z-graph/instance", Component: je(Se) },
2172
+ // catchall 放最后 —— 否则 `:rest*` 会先于具体路由匹配,导致 /z-graph/query
2173
+ // 全部跳进 GraphApp 的内层 /schema 路由(URL 变成 /z-graph/query/schema)。
2174
+ { path: "/z-graph/:rest*", Component: Ne }
2175
+ ];
2176
+ export {
2177
+ lt as HomePage,
2178
+ xt as LoginPage,
2179
+ W as api,
2180
+ gt as appMeta,
2181
+ bt as configureGraph,
2182
+ it as menuItems,
2183
+ yt as routes,
2184
+ Ge as useGraphServer,
2185
+ je as withGraphServer
2186
+ };