@lunora/studio 0.0.0 → 1.0.0-alpha.2

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.
Files changed (81) hide show
  1. package/LICENSE.md +105 -0
  2. package/README.md +123 -9
  3. package/__assets__/package-og.svg +14 -0
  4. package/dist/index.d.ts +1402 -0
  5. package/dist/index.js +41 -0
  6. package/dist/mount.d.ts +21 -0
  7. package/dist/mount.js +26 -0
  8. package/dist/packem_shared/ADMIN_FUNCTION_PREFIX-DmBqMZ-z.js +45 -0
  9. package/dist/packem_shared/ApiDocsPanel-DpRjJhG5.js +842 -0
  10. package/dist/packem_shared/ApiReferencePanel-DMIUp-kK.js +229 -0
  11. package/dist/packem_shared/ApiTab-DURGU15e.js +251 -0
  12. package/dist/packem_shared/AuditPanel-BC59Nhst.js +212 -0
  13. package/dist/packem_shared/CommandPalette-Dx_CoB9i.js +373 -0
  14. package/dist/packem_shared/ConfirmButton-WQVUoGFb.js +59 -0
  15. package/dist/packem_shared/ConnectionBadge-Bxagrip8.js +111 -0
  16. package/dist/packem_shared/DEFAULT_AUTO_REFRESH_MS-Vxwaxx51.js +50 -0
  17. package/dist/packem_shared/DEFAULT_INSIGHT_THRESHOLDS-DjF0h-gA.js +89 -0
  18. package/dist/packem_shared/DataBrowser-Coz6jJE6.js +4542 -0
  19. package/dist/packem_shared/DataFilters-FNquMaiu.js +249 -0
  20. package/dist/packem_shared/ErrorBoundary-BzAApI7J.js +66 -0
  21. package/dist/packem_shared/ExportImportPanel-WO34fJxy.js +193 -0
  22. package/dist/packem_shared/FileBrowser-Zcr-Qgxo.js +2932 -0
  23. package/dist/packem_shared/FunctionRunner-j0Rd5m9t.js +343 -0
  24. package/dist/packem_shared/FunctionStatsPanel-DboBl-XL.js +432 -0
  25. package/dist/packem_shared/GlobalDataBrowser-9MhPEfgN.js +318 -0
  26. package/dist/packem_shared/HealthPanel-DOIgbUtx.js +640 -0
  27. package/dist/packem_shared/HomePanel-bdOCNA-p.js +1273 -0
  28. package/dist/packem_shared/InsightsPanel-DaZPnSgt.js +423 -0
  29. package/dist/packem_shared/LogsPanel-CWdqAGpQ.js +839 -0
  30. package/dist/packem_shared/MailPanel-D_EGtDnS.js +447 -0
  31. package/dist/packem_shared/MetricsPanel-E4Gv6wTO.js +1625 -0
  32. package/dist/packem_shared/MigrationsPanel-DQdPY9io.js +246 -0
  33. package/dist/packem_shared/OpenRpcReferencePanel-j2p3HB0s.js +191 -0
  34. package/dist/packem_shared/PitrPanel-BbBkQR6t.js +252 -0
  35. package/dist/packem_shared/STUDIO_ROOT_CLASS-D12gX2dV.js +3 -0
  36. package/dist/packem_shared/ScheduledJobs-Ok1CYYwI.js +159 -0
  37. package/dist/packem_shared/SchemaViewer-D8XGnp-X.js +2512 -0
  38. package/dist/packem_shared/SecurityAdvisorPanel-Cdm2IxLW.js +79 -0
  39. package/dist/packem_shared/SettingsPanel-D3WF2mBU.js +176 -0
  40. package/dist/packem_shared/ShardInput-DNCsT1KW.js +107 -0
  41. package/dist/packem_shared/SqlEditorPanel-BuQ7f2Hs.js +13 -0
  42. package/dist/packem_shared/Studio-D36od9Oz.js +33 -0
  43. package/dist/packem_shared/StudioApp-dvywkJ8I.js +383 -0
  44. package/dist/packem_shared/StudioI18nProvider-Dcajsznk.js +48 -0
  45. package/dist/packem_shared/TableEditor-DIVDk3vT.js +371 -0
  46. package/dist/packem_shared/advisor-view-DBlzJi6C.js +159 -0
  47. package/dist/packem_shared/aggregateMetrics-D4nUHEKU.js +108 -0
  48. package/dist/packem_shared/app.d-CCmwDEVs.d.ts +300 -0
  49. package/dist/packem_shared/badge-B2PKA1-5.js +49 -0
  50. package/dist/packem_shared/bar-chart-CzJAgqkp.js +3245 -0
  51. package/dist/packem_shared/button-BhsN2uZH.js +49 -0
  52. package/dist/packem_shared/card-DURq3ElK.js +175 -0
  53. package/dist/packem_shared/cf-links-BZfRdxSE.js +8 -0
  54. package/dist/packem_shared/checkbox-UNkzAxl-.js +63 -0
  55. package/dist/packem_shared/createStudioI18n-CgvlmDkN.js +27 -0
  56. package/dist/packem_shared/data-grid-CCh2Couo.js +183 -0
  57. package/dist/packem_shared/dropdown-menu-WY4B_eJO.js +280 -0
  58. package/dist/packem_shared/empty-state-DY_oe0k6.js +98 -0
  59. package/dist/packem_shared/grid-features-DTjG6Sex.js +840 -0
  60. package/dist/packem_shared/input-XH4r1Pt1.js +53 -0
  61. package/dist/packem_shared/internal-BBZYexre.js +68 -0
  62. package/dist/packem_shared/label-D8ykjn5J.js +46 -0
  63. package/dist/packem_shared/live-status-bPff1O7Y.js +44 -0
  64. package/dist/packem_shared/reference-view-BCKIoai7.js +2180 -0
  65. package/dist/packem_shared/shard-history-DyebH1R5.js +38 -0
  66. package/dist/packem_shared/sparkline-10dG-_f0.js +93 -0
  67. package/dist/packem_shared/sql-editor-panel-CW2y2x9h.js +2562 -0
  68. package/dist/packem_shared/storage-tier-CL98eOvn.js +85 -0
  69. package/dist/packem_shared/studio-BDVd7rIV.js +10303 -0
  70. package/dist/packem_shared/table-_RzNvy3R.js +246 -0
  71. package/dist/packem_shared/table-list-sidebar-aZHLq70w.js +832 -0
  72. package/dist/packem_shared/textarea-D3gaCU_-.js +46 -0
  73. package/dist/packem_shared/use-live-admin-D1h1Fzsd.js +73 -0
  74. package/dist/packem_shared/use-live-shard-seed-B74RYcOy.js +76 -0
  75. package/dist/packem_shared/useDebounced-Dxncpg6z.js +32 -0
  76. package/dist/packem_shared/utils-B05Dmz_H.js +8 -0
  77. package/dist/packem_shared/virtual-rect-CVMUskSm.js +10 -0
  78. package/dist/standalone/studio.js +356 -0
  79. package/dist/styles.css +2 -0
  80. package/package.json +77 -17
  81. package/src/theme.css +59 -0
@@ -0,0 +1,2512 @@
1
+ 'use client';
2
+ import { c } from 'react/compiler-runtime';
3
+ import { useLunora } from '@lunora/react';
4
+ import { useState, useRef, useEffect } from 'react';
5
+ import { ShardInput } from './ShardInput-DNCsT1KW.js';
6
+ import { S as StorageTierBadge, T as TIER_META } from './storage-tier-CL98eOvn.js';
7
+ import { B as Badge } from './badge-B2PKA1-5.js';
8
+ import { B as Button } from './button-BhsN2uZH.js';
9
+ import { C as Card, b as CardHeader, c as CardTitle, d as CardDescription, a as CardContent } from './card-DURq3ElK.js';
10
+ import { E as EmptyState } from './empty-state-DY_oe0k6.js';
11
+ import { I as Input } from './input-XH4r1Pt1.js';
12
+ import useDebounced from './useDebounced-Dxncpg6z.js';
13
+ import { useT } from './createStudioI18n-CgvlmDkN.js';
14
+ import { ADMIN_FUNCTIONS } from './ADMIN_FUNCTION_PREFIX-DmBqMZ-z.js';
15
+ import { f as fireAndForget, c as callOptions, e as errorMessage, a as adminRef } from './internal-BBZYexre.js';
16
+ import { r as recordShard } from './shard-history-DyebH1R5.js';
17
+ import { c as cn } from './utils-B05Dmz_H.js';
18
+ import { Download01Icon } from '@hugeicons/core-free-icons';
19
+ import { HugeiconsIcon } from '@hugeicons/react';
20
+ import { Handle, Position, getNodesBounds, getViewportForBounds, useNodesState, useEdgesState, Background, Panel, Controls, MiniMap, ReactFlow, useNodes, useReactFlow } from '@xyflow/react';
21
+ import { d as DropdownMenu, D as DropdownMenuTrigger, c as DropdownMenuContent, b as DropdownMenuItem } from './dropdown-menu-WY4B_eJO.js';
22
+ import { jsxDEV } from 'react/jsx-dev-runtime';
23
+ import { toBlob, toSvg } from 'html-to-image';
24
+ import { useNavigate } from '@tanstack/react-router';
25
+ import { L as Label } from './label-D8ykjn5J.js';
26
+
27
+ function BaseNode(t0) {
28
+ const $ = c(10);
29
+ let className;
30
+ let props;
31
+ let selected;
32
+ if ($[0] !== t0) {
33
+ ({
34
+ className,
35
+ selected,
36
+ ...props
37
+ } = t0);
38
+ $[0] = t0;
39
+ $[1] = className;
40
+ $[2] = props;
41
+ $[3] = selected;
42
+ } else {
43
+ className = $[1];
44
+ props = $[2];
45
+ selected = $[3];
46
+ }
47
+ const t1 = selected === true ? "" : void 0;
48
+ let t2;
49
+ if ($[4] !== className) {
50
+ t2 = cn("rounded-md border border-border bg-card text-card-foreground shadow-sm transition-colors", "data-[selected]:border-ring data-[selected]:ring-[3px] data-[selected]:ring-ring/30", className);
51
+ $[4] = className;
52
+ $[5] = t2;
53
+ } else {
54
+ t2 = $[5];
55
+ }
56
+ let t3;
57
+ if ($[6] !== props || $[7] !== t1 || $[8] !== t2) {
58
+ t3 = /* @__PURE__ */ jsxDEV("div", {
59
+ "data-slot": "base-node",
60
+ "data-selected": t1,
61
+ className: t2,
62
+ ...props
63
+ }, void 0, false);
64
+ $[6] = props;
65
+ $[7] = t1;
66
+ $[8] = t2;
67
+ $[9] = t3;
68
+ } else {
69
+ t3 = $[9];
70
+ }
71
+ return t3;
72
+ }
73
+ function BaseNodeHeader(t0) {
74
+ const $ = c(8);
75
+ let className;
76
+ let props;
77
+ if ($[0] !== t0) {
78
+ ({
79
+ className,
80
+ ...props
81
+ } = t0);
82
+ $[0] = t0;
83
+ $[1] = className;
84
+ $[2] = props;
85
+ } else {
86
+ className = $[1];
87
+ props = $[2];
88
+ }
89
+ let t1;
90
+ if ($[3] !== className) {
91
+ t1 = cn("flex items-center gap-2 rounded-t-md bg-muted/50 px-3 py-1.5", className);
92
+ $[3] = className;
93
+ $[4] = t1;
94
+ } else {
95
+ t1 = $[4];
96
+ }
97
+ let t2;
98
+ if ($[5] !== props || $[6] !== t1) {
99
+ t2 = /* @__PURE__ */ jsxDEV("div", {
100
+ "data-slot": "base-node-header",
101
+ className: t1,
102
+ ...props
103
+ }, void 0, false);
104
+ $[5] = props;
105
+ $[6] = t1;
106
+ $[7] = t2;
107
+ } else {
108
+ t2 = $[7];
109
+ }
110
+ return t2;
111
+ }
112
+ function BaseNodeContent(t0) {
113
+ const $ = c(8);
114
+ let className;
115
+ let props;
116
+ if ($[0] !== t0) {
117
+ ({
118
+ className,
119
+ ...props
120
+ } = t0);
121
+ $[0] = t0;
122
+ $[1] = className;
123
+ $[2] = props;
124
+ } else {
125
+ className = $[1];
126
+ props = $[2];
127
+ }
128
+ let t1;
129
+ if ($[3] !== className) {
130
+ t1 = cn("flex flex-col", className);
131
+ $[3] = className;
132
+ $[4] = t1;
133
+ } else {
134
+ t1 = $[4];
135
+ }
136
+ let t2;
137
+ if ($[5] !== props || $[6] !== t1) {
138
+ t2 = /* @__PURE__ */ jsxDEV("div", {
139
+ "data-slot": "base-node-content",
140
+ className: t1,
141
+ ...props
142
+ }, void 0, false);
143
+ $[5] = props;
144
+ $[6] = t1;
145
+ $[7] = t2;
146
+ } else {
147
+ t2 = $[7];
148
+ }
149
+ return t2;
150
+ }
151
+
152
+ const typeLabel = (column) => {
153
+ const base = column.ref === void 0 ? column.type : `${column.type} → ${column.ref}`;
154
+ return column.optional === true ? `${base}?` : base;
155
+ };
156
+ const DatabaseSchemaNode = (t0) => {
157
+ const $ = c(22);
158
+ const {
159
+ data,
160
+ selected
161
+ } = t0;
162
+ const t = useT();
163
+ let t1;
164
+ if ($[0] !== data.label || $[1] !== data.loadError || $[2] !== t) {
165
+ t1 = data.loadError === true ? /* @__PURE__ */ jsxDEV("span", {
166
+ className: "px-3 py-1.5 text-xs text-destructive",
167
+ "data-testid": `sd-node-${data.label}-error`,
168
+ children: t("Columns unavailable")
169
+ }, void 0, false) : /* @__PURE__ */ jsxDEV("span", {
170
+ className: "px-3 py-1.5 text-xs text-muted-foreground",
171
+ children: "—"
172
+ }, void 0, false);
173
+ $[0] = data.label;
174
+ $[1] = data.loadError;
175
+ $[2] = t;
176
+ $[3] = t1;
177
+ } else {
178
+ t1 = $[3];
179
+ }
180
+ const emptyPlaceholder = t1;
181
+ const t2 = `sd-node-${data.label}`;
182
+ let t3;
183
+ if ($[4] !== data.label) {
184
+ t3 = /* @__PURE__ */ jsxDEV("span", {
185
+ className: "truncate font-mono text-xs font-semibold",
186
+ title: data.label,
187
+ children: data.label
188
+ }, void 0, false);
189
+ $[4] = data.label;
190
+ $[5] = t3;
191
+ } else {
192
+ t3 = $[5];
193
+ }
194
+ let t4;
195
+ if ($[6] !== data.tier) {
196
+ t4 = /* @__PURE__ */ jsxDEV("span", {
197
+ className: "ms-auto",
198
+ children: /* @__PURE__ */ jsxDEV(StorageTierBadge, {
199
+ tier: data.tier
200
+ }, void 0, false)
201
+ }, void 0, false);
202
+ $[6] = data.tier;
203
+ $[7] = t4;
204
+ } else {
205
+ t4 = $[7];
206
+ }
207
+ let t5;
208
+ if ($[8] !== t3 || $[9] !== t4) {
209
+ t5 = /* @__PURE__ */ jsxDEV(BaseNodeHeader, {
210
+ children: [t3, t4]
211
+ }, void 0, true);
212
+ $[8] = t3;
213
+ $[9] = t4;
214
+ $[10] = t5;
215
+ } else {
216
+ t5 = $[10];
217
+ }
218
+ let t6;
219
+ if ($[11] !== data.columns || $[12] !== data.label || $[13] !== emptyPlaceholder) {
220
+ t6 = data.columns.length === 0 ? emptyPlaceholder : data.columns.map((column) => /* @__PURE__ */ jsxDEV("div", {
221
+ className: cn("relative flex items-center gap-2 border-t border-border px-3 py-1.5 text-xs first:border-t-0", column.pk === true && "bg-muted/30"),
222
+ "data-testid": `sd-col-${data.label}-${column.name}`,
223
+ children: [/* @__PURE__ */ jsxDEV(Handle, {
224
+ className: "!h-2 !w-2 !-left-1 !border-border !bg-muted-foreground/70",
225
+ id: column.name,
226
+ isConnectable: false,
227
+ position: Position.Left,
228
+ type: "target"
229
+ }, void 0, false), /* @__PURE__ */ jsxDEV("span", {
230
+ className: "truncate font-mono",
231
+ title: column.name,
232
+ children: column.name
233
+ }, void 0, false), column.pk === true && /* @__PURE__ */ jsxDEV(Badge, {
234
+ className: "px-1 py-0 text-[10px] leading-tight",
235
+ variant: "secondary",
236
+ children: "PK"
237
+ }, void 0, false), column.ref !== void 0 && /* @__PURE__ */ jsxDEV(Badge, {
238
+ className: "px-1 py-0 text-[10px] leading-tight",
239
+ variant: "outline",
240
+ children: "FK"
241
+ }, void 0, false), /* @__PURE__ */ jsxDEV("span", {
242
+ className: "ms-auto truncate text-muted-foreground",
243
+ title: typeLabel(column),
244
+ children: typeLabel(column)
245
+ }, void 0, false), /* @__PURE__ */ jsxDEV(Handle, {
246
+ className: "!h-2 !w-2 !-right-1 !border-border !bg-muted-foreground/70",
247
+ id: column.name,
248
+ isConnectable: false,
249
+ position: Position.Right,
250
+ type: "source"
251
+ }, void 0, false)]
252
+ }, column.name, true));
253
+ $[11] = data.columns;
254
+ $[12] = data.label;
255
+ $[13] = emptyPlaceholder;
256
+ $[14] = t6;
257
+ } else {
258
+ t6 = $[14];
259
+ }
260
+ let t7;
261
+ if ($[15] !== t6) {
262
+ t7 = /* @__PURE__ */ jsxDEV(BaseNodeContent, {
263
+ children: t6
264
+ }, void 0, false);
265
+ $[15] = t6;
266
+ $[16] = t7;
267
+ } else {
268
+ t7 = $[16];
269
+ }
270
+ let t8;
271
+ if ($[17] !== selected || $[18] !== t2 || $[19] !== t5 || $[20] !== t7) {
272
+ t8 = /* @__PURE__ */ jsxDEV(BaseNode, {
273
+ className: "w-64 overflow-hidden",
274
+ "data-testid": t2,
275
+ selected,
276
+ children: [t5, t7]
277
+ }, void 0, true);
278
+ $[17] = selected;
279
+ $[18] = t2;
280
+ $[19] = t5;
281
+ $[20] = t7;
282
+ $[21] = t8;
283
+ } else {
284
+ t8 = $[21];
285
+ }
286
+ return t8;
287
+ };
288
+
289
+ const IMAGE_WIDTH = 1920;
290
+ const IMAGE_HEIGHT = 1080;
291
+ const IMAGE_PADDING = 32;
292
+ const triggerDownload = (href, filename) => {
293
+ const link = globalThis.document.createElement("a");
294
+ link.href = href;
295
+ link.download = filename;
296
+ globalThis.document.body.append(link);
297
+ link.click();
298
+ link.remove();
299
+ };
300
+ const exportDiagramAsJson = (nodes, edges, filename = "schema-diagram.json") => {
301
+ const payload = {
302
+ edges,
303
+ exportedAt: (/* @__PURE__ */ new Date()).toISOString(),
304
+ nodes
305
+ };
306
+ const json = JSON.stringify(payload, void 0, 2);
307
+ const url = globalThis.URL.createObjectURL(new globalThis.Blob([json], {
308
+ type: "application/json"
309
+ }));
310
+ triggerDownload(url, filename);
311
+ globalThis.setTimeout(() => {
312
+ globalThis.URL.revokeObjectURL(url);
313
+ }, 0);
314
+ };
315
+ const viewportForExport = (nodes, width, height, padding) => {
316
+ const bounds = getNodesBounds(nodes);
317
+ const {
318
+ x,
319
+ y,
320
+ zoom
321
+ } = getViewportForBounds(bounds, width, height, 0.1, 2, padding);
322
+ return {
323
+ transform: [x, y, zoom],
324
+ zoom
325
+ };
326
+ };
327
+ const exportDiagramAsPng = async (viewportElement, nodes, filename = "schema-diagram.png") => {
328
+ const {
329
+ transform
330
+ } = viewportForExport(nodes, IMAGE_WIDTH, IMAGE_HEIGHT, IMAGE_PADDING);
331
+ const [tx, ty, scale] = transform;
332
+ const blob = await toBlob(viewportElement, {
333
+ backgroundColor: "#ffffff",
334
+ height: IMAGE_HEIGHT,
335
+ style: {
336
+ transform: `translate(${tx.toString()}px, ${ty.toString()}px) scale(${scale.toString()})`,
337
+ transformOrigin: "top left",
338
+ width: `${IMAGE_WIDTH.toString()}px`
339
+ },
340
+ width: IMAGE_WIDTH
341
+ });
342
+ if (blob === null) {
343
+ throw new Error("html-to-image produced no blob");
344
+ }
345
+ const url = globalThis.URL.createObjectURL(blob);
346
+ triggerDownload(url, filename);
347
+ globalThis.setTimeout(() => {
348
+ globalThis.URL.revokeObjectURL(url);
349
+ }, 0);
350
+ };
351
+ const exportDiagramAsSvg = async (viewportElement, nodes, filename = "schema-diagram.svg") => {
352
+ const {
353
+ transform
354
+ } = viewportForExport(nodes, IMAGE_WIDTH, IMAGE_HEIGHT, IMAGE_PADDING);
355
+ const [tx, ty, scale] = transform;
356
+ const svgDataUrl = await toSvg(viewportElement, {
357
+ backgroundColor: "#ffffff",
358
+ height: IMAGE_HEIGHT,
359
+ style: {
360
+ transform: `translate(${tx.toString()}px, ${ty.toString()}px) scale(${scale.toString()})`,
361
+ transformOrigin: "top left",
362
+ width: `${IMAGE_WIDTH.toString()}px`
363
+ },
364
+ width: IMAGE_WIDTH
365
+ });
366
+ triggerDownload(svgDataUrl, filename);
367
+ };
368
+
369
+ const NODE_WIDTH = 256;
370
+ const COLUMN_GAP = 112;
371
+ const ROW_GAP = 36;
372
+ const PADDING = 24;
373
+ const HEADER_HEIGHT = 38;
374
+ const ROW_HEIGHT = 28;
375
+ const nodeHeight = (columnCount) => HEADER_HEIGHT + Math.max(1, columnCount) * ROW_HEIGHT;
376
+ const computeDepths = (tables, edges) => {
377
+ const targetsOf = /* @__PURE__ */ new Map();
378
+ for (const table of tables) {
379
+ targetsOf.set(table, []);
380
+ }
381
+ for (const edge of edges) {
382
+ if (edge.to !== edge.from && targetsOf.has(edge.from) && targetsOf.has(edge.to)) {
383
+ targetsOf.get(edge.from)?.push(edge.to);
384
+ }
385
+ }
386
+ const depth = /* @__PURE__ */ new Map();
387
+ const visiting = /* @__PURE__ */ new Set();
388
+ const resolve = (table) => {
389
+ const cached = depth.get(table);
390
+ if (cached !== void 0) {
391
+ return cached;
392
+ }
393
+ if (visiting.has(table)) {
394
+ return 0;
395
+ }
396
+ visiting.add(table);
397
+ let deepest = 0;
398
+ for (const target of targetsOf.get(table) ?? []) {
399
+ deepest = Math.max(deepest, resolve(target) + 1);
400
+ }
401
+ visiting.delete(table);
402
+ depth.set(table, deepest);
403
+ return deepest;
404
+ };
405
+ for (const table of tables) {
406
+ resolve(table);
407
+ }
408
+ return depth;
409
+ };
410
+ const computeLayout = (tables, edges, columnCounts) => {
411
+ const depth = computeDepths(tables, edges);
412
+ const offsetByColumn = /* @__PURE__ */ new Map();
413
+ const nodes = [];
414
+ for (const name of tables) {
415
+ const column = depth.get(name) ?? 0;
416
+ const y = offsetByColumn.get(column) ?? PADDING;
417
+ nodes.push({
418
+ name,
419
+ x: PADDING + column * (NODE_WIDTH + COLUMN_GAP),
420
+ y
421
+ });
422
+ offsetByColumn.set(column, y + nodeHeight(columnCounts.get(name) ?? 0) + ROW_GAP);
423
+ }
424
+ return nodes;
425
+ };
426
+
427
+ const NODE_TYPES = {
428
+ databaseSchema: DatabaseSchemaNode
429
+ };
430
+ const SHARD_DOT_STYLE = {
431
+ backgroundColor: TIER_META.shard.color
432
+ };
433
+ const GLOBAL_DOT_STYLE = {
434
+ backgroundColor: TIER_META.global.color
435
+ };
436
+ const ALL_TIERS = {
437
+ global: true,
438
+ shard: true
439
+ };
440
+ const pkColumnOf = (columns) => {
441
+ const flagged = columns.find((column) => column.pk === true)?.name;
442
+ if (flagged !== void 0) {
443
+ return flagged;
444
+ }
445
+ if (columns.some((column) => column.name === "_id")) {
446
+ return "_id";
447
+ }
448
+ if (columns.some((column) => column.name === "id")) {
449
+ return "id";
450
+ }
451
+ return columns[0]?.name ?? "_id";
452
+ };
453
+ const deriveEdges = (tables) => tables.flatMap((table) => table.columns.filter((column) => column.ref !== void 0).map((column) => {
454
+ return {
455
+ column: column.name,
456
+ from: table.name,
457
+ to: column.ref
458
+ };
459
+ }));
460
+ const buildNodes = (tables, columnsError) => {
461
+ const names = tables.map((table) => table.name);
462
+ const counts = new Map(tables.map((table) => [table.name, table.columns.length]));
463
+ const positions = computeLayout(names, deriveEdges(tables), counts);
464
+ const byName = new Map(tables.map((table) => [table.name, table]));
465
+ return positions.flatMap(({
466
+ name,
467
+ x,
468
+ y
469
+ }) => {
470
+ const table = byName.get(name);
471
+ if (table === void 0) {
472
+ return [];
473
+ }
474
+ return [{
475
+ data: {
476
+ columns: table.columns,
477
+ label: name,
478
+ loadError: columnsError,
479
+ tier: table.tier
480
+ },
481
+ id: name,
482
+ position: {
483
+ x,
484
+ y
485
+ },
486
+ type: "databaseSchema"
487
+ }];
488
+ });
489
+ };
490
+ const buildEdges = (tables) => {
491
+ const columnsByTable = new Map(tables.map((table) => [table.name, table.columns]));
492
+ return deriveEdges(tables).flatMap((edge) => {
493
+ const targetColumns = columnsByTable.get(edge.to) ?? [];
494
+ const sourceColumns = columnsByTable.get(edge.from) ?? [];
495
+ const pk = pkColumnOf(targetColumns);
496
+ if (!targetColumns.some((column) => column.name === pk) || !sourceColumns.some((column) => column.name === edge.column)) {
497
+ return [];
498
+ }
499
+ return [{
500
+ id: `${edge.from}.${edge.column}->${edge.to}`,
501
+ source: edge.to,
502
+ sourceHandle: pk,
503
+ target: edge.from,
504
+ targetHandle: edge.column
505
+ }];
506
+ });
507
+ };
508
+ const Legend = () => {
509
+ const $ = c(15);
510
+ const t = useT();
511
+ let t0;
512
+ if ($[0] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
513
+ t0 = /* @__PURE__ */ jsxDEV("span", {
514
+ className: "flex items-center gap-1",
515
+ children: [/* @__PURE__ */ jsxDEV("span", {
516
+ "aria-hidden": "true",
517
+ className: "size-1.5 rounded-full",
518
+ style: SHARD_DOT_STYLE
519
+ }, void 0, false), TIER_META.shard.label]
520
+ }, void 0, true);
521
+ $[0] = t0;
522
+ } else {
523
+ t0 = $[0];
524
+ }
525
+ let t1;
526
+ if ($[1] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
527
+ t1 = /* @__PURE__ */ jsxDEV("span", {
528
+ className: "flex items-center gap-1",
529
+ children: [/* @__PURE__ */ jsxDEV("span", {
530
+ "aria-hidden": "true",
531
+ className: "size-1.5 rounded-full",
532
+ style: GLOBAL_DOT_STYLE
533
+ }, void 0, false), TIER_META.global.label]
534
+ }, void 0, true);
535
+ $[1] = t1;
536
+ } else {
537
+ t1 = $[1];
538
+ }
539
+ let t2;
540
+ if ($[2] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
541
+ t2 = /* @__PURE__ */ jsxDEV(Badge, {
542
+ className: "px-1 py-0 text-[10px] leading-tight",
543
+ variant: "secondary",
544
+ children: "PK"
545
+ }, void 0, false);
546
+ $[2] = t2;
547
+ } else {
548
+ t2 = $[2];
549
+ }
550
+ let t3;
551
+ if ($[3] !== t) {
552
+ t3 = t("Primary key");
553
+ $[3] = t;
554
+ $[4] = t3;
555
+ } else {
556
+ t3 = $[4];
557
+ }
558
+ let t4;
559
+ if ($[5] !== t3) {
560
+ t4 = /* @__PURE__ */ jsxDEV("span", {
561
+ className: "flex items-center gap-1",
562
+ children: [t2, t3]
563
+ }, void 0, true);
564
+ $[5] = t3;
565
+ $[6] = t4;
566
+ } else {
567
+ t4 = $[6];
568
+ }
569
+ let t5;
570
+ if ($[7] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
571
+ t5 = /* @__PURE__ */ jsxDEV(Badge, {
572
+ className: "px-1 py-0 text-[10px] leading-tight",
573
+ variant: "outline",
574
+ children: "FK"
575
+ }, void 0, false);
576
+ $[7] = t5;
577
+ } else {
578
+ t5 = $[7];
579
+ }
580
+ let t6;
581
+ if ($[8] !== t) {
582
+ t6 = t("Foreign key");
583
+ $[8] = t;
584
+ $[9] = t6;
585
+ } else {
586
+ t6 = $[9];
587
+ }
588
+ let t7;
589
+ if ($[10] !== t6) {
590
+ t7 = /* @__PURE__ */ jsxDEV("span", {
591
+ className: "flex items-center gap-1",
592
+ children: [t5, t6]
593
+ }, void 0, true);
594
+ $[10] = t6;
595
+ $[11] = t7;
596
+ } else {
597
+ t7 = $[11];
598
+ }
599
+ let t8;
600
+ if ($[12] !== t4 || $[13] !== t7) {
601
+ t8 = /* @__PURE__ */ jsxDEV("div", {
602
+ className: "flex flex-wrap items-center gap-x-3 gap-y-1 rounded-xl border border-border bg-card/95 px-2.5 py-1.5 text-[11px] text-muted-foreground shadow-xs",
603
+ children: [t0, t1, t4, t7]
604
+ }, void 0, true);
605
+ $[12] = t4;
606
+ $[13] = t7;
607
+ $[14] = t8;
608
+ } else {
609
+ t8 = $[14];
610
+ }
611
+ return t8;
612
+ };
613
+ const DiagramExportPanel = ({
614
+ containerRef,
615
+ testIdPrefix
616
+ }) => {
617
+ const t = useT();
618
+ const nodes = useNodes();
619
+ const {
620
+ getEdges
621
+ } = useReactFlow();
622
+ const [exporting, setExporting] = useState(null);
623
+ const handlePng = async () => {
624
+ const viewport = containerRef.current?.querySelector(".react-flow__viewport");
625
+ if (!viewport) {
626
+ return;
627
+ }
628
+ setExporting("png");
629
+ try {
630
+ await exportDiagramAsPng(viewport, nodes, `${testIdPrefix}-schema-diagram.png`);
631
+ } finally {
632
+ setExporting(null);
633
+ }
634
+ };
635
+ const handleSvg = async () => {
636
+ const viewport_0 = containerRef.current?.querySelector(".react-flow__viewport");
637
+ if (!viewport_0) {
638
+ return;
639
+ }
640
+ setExporting("svg");
641
+ try {
642
+ await exportDiagramAsSvg(viewport_0, nodes, `${testIdPrefix}-schema-diagram.svg`);
643
+ } finally {
644
+ setExporting(null);
645
+ }
646
+ };
647
+ const handleJson = () => {
648
+ setExporting("json");
649
+ try {
650
+ exportDiagramAsJson(nodes, getEdges(), `${testIdPrefix}-schema-diagram.json`);
651
+ } finally {
652
+ setExporting(null);
653
+ }
654
+ };
655
+ const onClickPng = () => {
656
+ fireAndForget(handlePng());
657
+ };
658
+ const onClickSvg = () => {
659
+ fireAndForget(handleSvg());
660
+ };
661
+ return /* @__PURE__ */ jsxDEV(Panel, {
662
+ position: "top-right",
663
+ children: /* @__PURE__ */ jsxDEV(DropdownMenu, {
664
+ children: [/* @__PURE__ */ jsxDEV(DropdownMenuTrigger, {
665
+ className: "group/button inline-flex shrink-0 cursor-pointer items-center justify-center gap-1 rounded-md border border-border bg-background px-2 text-xs font-medium whitespace-nowrap hover:bg-muted disabled:pointer-events-none disabled:opacity-50",
666
+ "data-testid": `${testIdPrefix}-export-trigger`,
667
+ disabled: exporting !== null,
668
+ children: [/* @__PURE__ */ jsxDEV(HugeiconsIcon, {
669
+ className: "size-3.5",
670
+ icon: Download01Icon,
671
+ strokeWidth: 2
672
+ }, void 0, false), t("Export")]
673
+ }, void 0, true), /* @__PURE__ */ jsxDEV(DropdownMenuContent, {
674
+ align: "end",
675
+ children: [/* @__PURE__ */ jsxDEV(DropdownMenuItem, {
676
+ "data-testid": `${testIdPrefix}-export-png`,
677
+ disabled: exporting !== null,
678
+ onClick: onClickPng,
679
+ children: t("PNG")
680
+ }, void 0, false), /* @__PURE__ */ jsxDEV(DropdownMenuItem, {
681
+ "data-testid": `${testIdPrefix}-export-svg`,
682
+ disabled: exporting !== null,
683
+ onClick: onClickSvg,
684
+ children: t("SVG")
685
+ }, void 0, false), /* @__PURE__ */ jsxDEV(DropdownMenuItem, {
686
+ "data-testid": `${testIdPrefix}-export-json`,
687
+ disabled: exporting !== null,
688
+ onClick: handleJson,
689
+ children: t("JSON")
690
+ }, void 0, false)]
691
+ }, void 0, true)]
692
+ }, void 0, true)
693
+ }, void 0, false);
694
+ };
695
+ const SchemaDiagram = (t0) => {
696
+ const $ = c(75);
697
+ const {
698
+ columnsError,
699
+ tables,
700
+ testIdPrefix
701
+ } = t0;
702
+ const t = useT();
703
+ const [tierFilter, setTierFilter] = useState(ALL_TIERS);
704
+ const [query, setQuery] = useState("");
705
+ let t1;
706
+ if ($[0] !== query || $[1] !== tables || $[2] !== tierFilter) {
707
+ const needle = query.trim().toLowerCase();
708
+ t1 = tables.filter((table) => tierFilter[table.tier] && table.name.toLowerCase().includes(needle));
709
+ $[0] = query;
710
+ $[1] = tables;
711
+ $[2] = tierFilter;
712
+ $[3] = t1;
713
+ } else {
714
+ t1 = $[3];
715
+ }
716
+ const visibleTables = t1;
717
+ const t2 = columnsError ?? false;
718
+ let t3;
719
+ if ($[4] !== t2 || $[5] !== visibleTables) {
720
+ t3 = buildNodes(visibleTables, t2);
721
+ $[4] = t2;
722
+ $[5] = visibleTables;
723
+ $[6] = t3;
724
+ } else {
725
+ t3 = $[6];
726
+ }
727
+ const seededNodes = t3;
728
+ let t4;
729
+ if ($[7] !== visibleTables) {
730
+ t4 = buildEdges(visibleTables);
731
+ $[7] = visibleTables;
732
+ $[8] = t4;
733
+ } else {
734
+ t4 = $[8];
735
+ }
736
+ const seededEdges = t4;
737
+ const [nodes, setNodes, onNodesChange] = useNodesState(seededNodes);
738
+ const [flowEdges, setEdges, onEdgesChange] = useEdgesState(seededEdges);
739
+ const canvasRef = useRef(null);
740
+ let t5;
741
+ let t6;
742
+ if ($[9] !== seededNodes || $[10] !== setNodes) {
743
+ t5 = () => {
744
+ setNodes(seededNodes);
745
+ };
746
+ t6 = [seededNodes, setNodes];
747
+ $[9] = seededNodes;
748
+ $[10] = setNodes;
749
+ $[11] = t5;
750
+ $[12] = t6;
751
+ } else {
752
+ t5 = $[11];
753
+ t6 = $[12];
754
+ }
755
+ useEffect(t5, t6);
756
+ let t7;
757
+ let t8;
758
+ if ($[13] !== seededEdges || $[14] !== setEdges) {
759
+ t7 = () => {
760
+ setEdges(seededEdges);
761
+ };
762
+ t8 = [seededEdges, setEdges];
763
+ $[13] = seededEdges;
764
+ $[14] = setEdges;
765
+ $[15] = t7;
766
+ $[16] = t8;
767
+ } else {
768
+ t7 = $[15];
769
+ t8 = $[16];
770
+ }
771
+ useEffect(t7, t8);
772
+ let t9;
773
+ if ($[17] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
774
+ t9 = (event) => {
775
+ setQuery(event.target.value);
776
+ };
777
+ $[17] = t9;
778
+ } else {
779
+ t9 = $[17];
780
+ }
781
+ const onQueryChange = t9;
782
+ let t10;
783
+ if ($[18] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
784
+ t10 = () => {
785
+ setTierFilter(_temp$1);
786
+ };
787
+ $[18] = t10;
788
+ } else {
789
+ t10 = $[18];
790
+ }
791
+ const toggleShard = t10;
792
+ let t11;
793
+ if ($[19] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
794
+ t11 = () => {
795
+ setTierFilter(_temp2$1);
796
+ };
797
+ $[19] = t11;
798
+ } else {
799
+ t11 = $[19];
800
+ }
801
+ const toggleGlobal = t11;
802
+ if (tables.length === 0) {
803
+ const t122 = `${testIdPrefix}-section`;
804
+ const t132 = `${testIdPrefix}-empty`;
805
+ let t142;
806
+ if ($[20] !== t) {
807
+ t142 = t("No tables to graph.");
808
+ $[20] = t;
809
+ $[21] = t142;
810
+ } else {
811
+ t142 = $[21];
812
+ }
813
+ let t152;
814
+ if ($[22] !== t132 || $[23] !== t142) {
815
+ t152 = /* @__PURE__ */ jsxDEV("p", {
816
+ className: "text-sm text-muted-foreground",
817
+ "data-testid": t132,
818
+ children: t142
819
+ }, void 0, false);
820
+ $[22] = t132;
821
+ $[23] = t142;
822
+ $[24] = t152;
823
+ } else {
824
+ t152 = $[24];
825
+ }
826
+ let t162;
827
+ if ($[25] !== t122 || $[26] !== t152) {
828
+ t162 = /* @__PURE__ */ jsxDEV("section", {
829
+ className: "flex flex-col gap-2",
830
+ "data-testid": t122,
831
+ children: t152
832
+ }, void 0, false);
833
+ $[25] = t122;
834
+ $[26] = t152;
835
+ $[27] = t162;
836
+ } else {
837
+ t162 = $[27];
838
+ }
839
+ return t162;
840
+ }
841
+ const t12 = `${testIdPrefix}-section`;
842
+ const t13 = `${testIdPrefix}-canvas`;
843
+ let t14;
844
+ if ($[28] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
845
+ t14 = /* @__PURE__ */ jsxDEV(Background, {}, void 0, false);
846
+ $[28] = t14;
847
+ } else {
848
+ t14 = $[28];
849
+ }
850
+ let t15;
851
+ if ($[29] !== t) {
852
+ t15 = t("Find table…");
853
+ $[29] = t;
854
+ $[30] = t15;
855
+ } else {
856
+ t15 = $[30];
857
+ }
858
+ const t16 = `${testIdPrefix}-find`;
859
+ let t17;
860
+ if ($[31] !== t) {
861
+ t17 = t("Find table…");
862
+ $[31] = t;
863
+ $[32] = t17;
864
+ } else {
865
+ t17 = $[32];
866
+ }
867
+ let t18;
868
+ if ($[33] !== query || $[34] !== t15 || $[35] !== t16 || $[36] !== t17) {
869
+ t18 = /* @__PURE__ */ jsxDEV(Input, {
870
+ "aria-label": t15,
871
+ className: "h-7 w-44 text-xs",
872
+ "data-testid": t16,
873
+ onChange: onQueryChange,
874
+ placeholder: t17,
875
+ value: query
876
+ }, void 0, false);
877
+ $[33] = query;
878
+ $[34] = t15;
879
+ $[35] = t16;
880
+ $[36] = t17;
881
+ $[37] = t18;
882
+ } else {
883
+ t18 = $[37];
884
+ }
885
+ let t19;
886
+ if ($[38] !== t) {
887
+ t19 = t("Storage tiers");
888
+ $[38] = t;
889
+ $[39] = t19;
890
+ } else {
891
+ t19 = $[39];
892
+ }
893
+ const t20 = `${testIdPrefix}-tier-shard`;
894
+ const t21 = tierFilter.shard ? "default" : "outline";
895
+ let t22;
896
+ if ($[40] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
897
+ t22 = /* @__PURE__ */ jsxDEV("span", {
898
+ "aria-hidden": "true",
899
+ className: "size-1.5 rounded-full",
900
+ style: SHARD_DOT_STYLE
901
+ }, void 0, false);
902
+ $[40] = t22;
903
+ } else {
904
+ t22 = $[40];
905
+ }
906
+ let t23;
907
+ if ($[41] !== t20 || $[42] !== t21 || $[43] !== tierFilter.shard) {
908
+ t23 = /* @__PURE__ */ jsxDEV(Button, {
909
+ "aria-pressed": tierFilter.shard,
910
+ className: "gap-1.5",
911
+ "data-testid": t20,
912
+ onClick: toggleShard,
913
+ size: "xs",
914
+ type: "button",
915
+ variant: t21,
916
+ children: [t22, TIER_META.shard.label]
917
+ }, void 0, true);
918
+ $[41] = t20;
919
+ $[42] = t21;
920
+ $[43] = tierFilter.shard;
921
+ $[44] = t23;
922
+ } else {
923
+ t23 = $[44];
924
+ }
925
+ const t24 = `${testIdPrefix}-tier-global`;
926
+ const t25 = tierFilter.global ? "default" : "outline";
927
+ let t26;
928
+ if ($[45] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
929
+ t26 = /* @__PURE__ */ jsxDEV("span", {
930
+ "aria-hidden": "true",
931
+ className: "size-1.5 rounded-full",
932
+ style: GLOBAL_DOT_STYLE
933
+ }, void 0, false);
934
+ $[45] = t26;
935
+ } else {
936
+ t26 = $[45];
937
+ }
938
+ let t27;
939
+ if ($[46] !== t24 || $[47] !== t25 || $[48] !== tierFilter.global) {
940
+ t27 = /* @__PURE__ */ jsxDEV(Button, {
941
+ "aria-pressed": tierFilter.global,
942
+ className: "gap-1.5",
943
+ "data-testid": t24,
944
+ onClick: toggleGlobal,
945
+ size: "xs",
946
+ type: "button",
947
+ variant: t25,
948
+ children: [t26, TIER_META.global.label]
949
+ }, void 0, true);
950
+ $[46] = t24;
951
+ $[47] = t25;
952
+ $[48] = tierFilter.global;
953
+ $[49] = t27;
954
+ } else {
955
+ t27 = $[49];
956
+ }
957
+ let t28;
958
+ if ($[50] !== t19 || $[51] !== t23 || $[52] !== t27) {
959
+ t28 = /* @__PURE__ */ jsxDEV("div", {
960
+ "aria-label": t19,
961
+ className: "flex items-center gap-1.5",
962
+ role: "group",
963
+ children: [t23, t27]
964
+ }, void 0, true);
965
+ $[50] = t19;
966
+ $[51] = t23;
967
+ $[52] = t27;
968
+ $[53] = t28;
969
+ } else {
970
+ t28 = $[53];
971
+ }
972
+ let t29;
973
+ if ($[54] !== t18 || $[55] !== t28) {
974
+ t29 = /* @__PURE__ */ jsxDEV(Panel, {
975
+ position: "top-left",
976
+ children: /* @__PURE__ */ jsxDEV("div", {
977
+ className: "flex flex-col gap-2 rounded-xl border border-border bg-card/95 p-2 shadow-xs",
978
+ children: [t18, t28]
979
+ }, void 0, true)
980
+ }, void 0, false);
981
+ $[54] = t18;
982
+ $[55] = t28;
983
+ $[56] = t29;
984
+ } else {
985
+ t29 = $[56];
986
+ }
987
+ let t30;
988
+ let t31;
989
+ let t32;
990
+ if ($[57] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
991
+ t30 = /* @__PURE__ */ jsxDEV(Panel, {
992
+ position: "bottom-left",
993
+ children: /* @__PURE__ */ jsxDEV(Legend, {}, void 0, false)
994
+ }, void 0, false);
995
+ t31 = /* @__PURE__ */ jsxDEV(Controls, {
996
+ showInteractive: false
997
+ }, void 0, false);
998
+ t32 = /* @__PURE__ */ jsxDEV(MiniMap, {
999
+ pannable: true,
1000
+ zoomable: true
1001
+ }, void 0, false);
1002
+ $[57] = t30;
1003
+ $[58] = t31;
1004
+ $[59] = t32;
1005
+ } else {
1006
+ t30 = $[57];
1007
+ t31 = $[58];
1008
+ t32 = $[59];
1009
+ }
1010
+ let t33;
1011
+ if ($[60] !== testIdPrefix) {
1012
+ t33 = /* @__PURE__ */ jsxDEV(DiagramExportPanel, {
1013
+ containerRef: canvasRef,
1014
+ testIdPrefix
1015
+ }, void 0, false);
1016
+ $[60] = testIdPrefix;
1017
+ $[61] = t33;
1018
+ } else {
1019
+ t33 = $[61];
1020
+ }
1021
+ let t34;
1022
+ if ($[62] !== flowEdges || $[63] !== nodes || $[64] !== onEdgesChange || $[65] !== onNodesChange || $[66] !== t29 || $[67] !== t33) {
1023
+ t34 = /* @__PURE__ */ jsxDEV(ReactFlow, {
1024
+ edges: flowEdges,
1025
+ elementsSelectable: true,
1026
+ fitView: true,
1027
+ minZoom: 0.2,
1028
+ nodes,
1029
+ nodesConnectable: false,
1030
+ nodeTypes: NODE_TYPES,
1031
+ onEdgesChange,
1032
+ onNodesChange,
1033
+ children: [t14, t29, t30, t31, t32, t33]
1034
+ }, void 0, true);
1035
+ $[62] = flowEdges;
1036
+ $[63] = nodes;
1037
+ $[64] = onEdgesChange;
1038
+ $[65] = onNodesChange;
1039
+ $[66] = t29;
1040
+ $[67] = t33;
1041
+ $[68] = t34;
1042
+ } else {
1043
+ t34 = $[68];
1044
+ }
1045
+ let t35;
1046
+ if ($[69] !== t13 || $[70] !== t34) {
1047
+ t35 = /* @__PURE__ */ jsxDEV("div", {
1048
+ className: "h-[560px] w-full overflow-hidden rounded-xl border border-border bg-muted/20 shadow-xs",
1049
+ "data-testid": t13,
1050
+ ref: canvasRef,
1051
+ children: t34
1052
+ }, void 0, false);
1053
+ $[69] = t13;
1054
+ $[70] = t34;
1055
+ $[71] = t35;
1056
+ } else {
1057
+ t35 = $[71];
1058
+ }
1059
+ let t36;
1060
+ if ($[72] !== t12 || $[73] !== t35) {
1061
+ t36 = /* @__PURE__ */ jsxDEV("section", {
1062
+ className: "flex flex-col gap-2",
1063
+ "data-testid": t12,
1064
+ children: t35
1065
+ }, void 0, false);
1066
+ $[72] = t12;
1067
+ $[73] = t35;
1068
+ $[74] = t36;
1069
+ } else {
1070
+ t36 = $[74];
1071
+ }
1072
+ return t36;
1073
+ };
1074
+ function _temp$1(previous) {
1075
+ return {
1076
+ ...previous,
1077
+ shard: !previous.shard
1078
+ };
1079
+ }
1080
+ function _temp2$1(previous_0) {
1081
+ return {
1082
+ ...previous_0,
1083
+ global: !previous_0.global
1084
+ };
1085
+ }
1086
+
1087
+ const SCHEMA_EDIT_ENDPOINT = "/__lunora/schema-edit";
1088
+ const applyEdit = async (edit) => {
1089
+ const response = await fetch(SCHEMA_EDIT_ENDPOINT, {
1090
+ body: JSON.stringify(edit),
1091
+ // `Content-Type: application/json` is non-simple and forces a CORS preflight
1092
+ // for cross-origin fetches, preventing CSRF via the browser's same-origin
1093
+ // policy. `X-Lunora-Studio` is an additional custom header that also triggers
1094
+ // a preflight and lets the server-side guard identify studio traffic; both
1095
+ // headers are checked by the `@lunora/config` `csrfRejectionReason` guard.
1096
+ headers: {
1097
+ "Content-Type": "application/json",
1098
+ "X-Lunora-Studio": "1"
1099
+ },
1100
+ method: "POST"
1101
+ });
1102
+ const body = await response.json();
1103
+ if (body.needsMigration === true) {
1104
+ return {
1105
+ kind: "needs-migration",
1106
+ message: body.message ?? "This edit needs a migration."
1107
+ };
1108
+ }
1109
+ if (response.ok && body.tables !== void 0) {
1110
+ return {
1111
+ diagnostics: body.diagnostics ?? [],
1112
+ kind: "ok",
1113
+ tables: body.tables
1114
+ };
1115
+ }
1116
+ return {
1117
+ kind: "error",
1118
+ message: body.error ?? `schema edit failed (${String(response.status)})`
1119
+ };
1120
+ };
1121
+
1122
+ const COLUMN_TYPES = [{
1123
+ label: "string",
1124
+ validator: "v.string()"
1125
+ }, {
1126
+ label: "number",
1127
+ validator: "v.number()"
1128
+ }, {
1129
+ label: "boolean",
1130
+ validator: "v.boolean()"
1131
+ }, {
1132
+ label: "bigint",
1133
+ validator: "v.int64()"
1134
+ }, {
1135
+ label: "bytes",
1136
+ validator: "v.bytes()"
1137
+ }, {
1138
+ label: "any",
1139
+ validator: "v.any()"
1140
+ }];
1141
+ const DEFAULT_VALIDATOR = "v.string()";
1142
+ const splitFields = (raw) => raw.split(",").map((field) => field.trim()).filter((field) => field !== "");
1143
+ const SchemaEditorOverlay = ({
1144
+ onApplied,
1145
+ tableNames
1146
+ }) => {
1147
+ const t = useT();
1148
+ const navigate = useNavigate();
1149
+ const [mode, setMode] = useState(null);
1150
+ const [busy, setBusy] = useState(false);
1151
+ const [result, setResult] = useState(null);
1152
+ const [tableName, setTableName] = useState("");
1153
+ const [columnName, setColumnName] = useState("");
1154
+ const [validator, setValidator] = useState(DEFAULT_VALIDATOR);
1155
+ const [targetTable, setTargetTable] = useState(tableNames[0] ?? "");
1156
+ const [indexName, setIndexName] = useState("");
1157
+ const [indexFields, setIndexFields] = useState("");
1158
+ const [unique, setUnique] = useState(false);
1159
+ const reset = () => {
1160
+ setMode(null);
1161
+ setTableName("");
1162
+ setColumnName("");
1163
+ setIndexName("");
1164
+ setIndexFields("");
1165
+ setUnique(false);
1166
+ };
1167
+ const submit = async (edit) => {
1168
+ setBusy(true);
1169
+ setResult(null);
1170
+ try {
1171
+ const outcome = await applyEdit(edit);
1172
+ setResult(outcome);
1173
+ if (outcome.kind === "ok") {
1174
+ onApplied(outcome.tables);
1175
+ reset();
1176
+ }
1177
+ } catch (error) {
1178
+ setResult({
1179
+ kind: "error",
1180
+ message: error instanceof Error ? error.message : String(error)
1181
+ });
1182
+ } finally {
1183
+ setBusy(false);
1184
+ }
1185
+ };
1186
+ const onSubmitTable = () => {
1187
+ fireAndForget(submit({
1188
+ kind: "addTable",
1189
+ table: tableName.trim()
1190
+ }));
1191
+ };
1192
+ const onSubmitColumn = () => {
1193
+ fireAndForget(submit({
1194
+ column: columnName.trim(),
1195
+ kind: "addOptionalColumn",
1196
+ table: targetTable,
1197
+ validator
1198
+ }));
1199
+ };
1200
+ const onSubmitIndex = () => {
1201
+ fireAndForget(submit({
1202
+ fields: splitFields(indexFields),
1203
+ kind: "addIndex",
1204
+ name: indexName.trim(),
1205
+ table: targetTable,
1206
+ unique
1207
+ }));
1208
+ };
1209
+ const openTable = () => {
1210
+ setResult(null);
1211
+ setMode("addTable");
1212
+ };
1213
+ const openColumn = () => {
1214
+ setResult(null);
1215
+ setMode("addColumn");
1216
+ };
1217
+ const openIndex = () => {
1218
+ setResult(null);
1219
+ setMode("addIndex");
1220
+ };
1221
+ const openDestructive = () => {
1222
+ setMode("destructive");
1223
+ setResult({
1224
+ kind: "needs-migration",
1225
+ message: t("This edit changes stored data and must go through a migration. Review the migration before applying.")
1226
+ });
1227
+ };
1228
+ const onTableNameChange = (event) => {
1229
+ setTableName(event.target.value);
1230
+ };
1231
+ const onColumnNameChange = (event_0) => {
1232
+ setColumnName(event_0.target.value);
1233
+ };
1234
+ const onValidatorChange = (event_1) => {
1235
+ setValidator(event_1.target.value);
1236
+ };
1237
+ const onTargetTableChange = (event_2) => {
1238
+ setTargetTable(event_2.target.value);
1239
+ };
1240
+ const onIndexNameChange = (event_3) => {
1241
+ setIndexName(event_3.target.value);
1242
+ };
1243
+ const onIndexFieldsChange = (event_4) => {
1244
+ setIndexFields(event_4.target.value);
1245
+ };
1246
+ const onUniqueChange = (event_5) => {
1247
+ setUnique(event_5.target.checked);
1248
+ };
1249
+ const onOpenMigrations = () => {
1250
+ fireAndForget(navigate({
1251
+ to: "/migrations"
1252
+ }));
1253
+ };
1254
+ return /* @__PURE__ */ jsxDEV(Card, {
1255
+ "data-testid": "sc-editor",
1256
+ size: "sm",
1257
+ children: [/* @__PURE__ */ jsxDEV(CardHeader, {
1258
+ children: [/* @__PURE__ */ jsxDEV(CardTitle, {
1259
+ children: t("Edit schema")
1260
+ }, void 0, false), /* @__PURE__ */ jsxDEV(CardDescription, {
1261
+ children: t("Adds a table, column, or index to lunora/schema.ts and reruns codegen.")
1262
+ }, void 0, false)]
1263
+ }, void 0, true), /* @__PURE__ */ jsxDEV(CardContent, {
1264
+ children: [/* @__PURE__ */ jsxDEV("div", {
1265
+ className: "flex flex-wrap gap-2",
1266
+ children: [/* @__PURE__ */ jsxDEV(Button, {
1267
+ "data-testid": "sc-editor-add-table",
1268
+ onClick: openTable,
1269
+ size: "xs",
1270
+ type: "button",
1271
+ variant: mode === "addTable" ? "default" : "outline",
1272
+ children: t("Add table")
1273
+ }, void 0, false), /* @__PURE__ */ jsxDEV(Button, {
1274
+ "data-testid": "sc-editor-add-column",
1275
+ disabled: tableNames.length === 0,
1276
+ onClick: openColumn,
1277
+ size: "xs",
1278
+ type: "button",
1279
+ variant: mode === "addColumn" ? "default" : "outline",
1280
+ children: t("Add column")
1281
+ }, void 0, false), /* @__PURE__ */ jsxDEV(Button, {
1282
+ "data-testid": "sc-editor-add-index",
1283
+ disabled: tableNames.length === 0,
1284
+ onClick: openIndex,
1285
+ size: "xs",
1286
+ type: "button",
1287
+ variant: mode === "addIndex" ? "default" : "outline",
1288
+ children: t("Add index")
1289
+ }, void 0, false), /* @__PURE__ */ jsxDEV(Button, {
1290
+ "data-testid": "sc-editor-destructive",
1291
+ disabled: tableNames.length === 0,
1292
+ onClick: openDestructive,
1293
+ size: "xs",
1294
+ type: "button",
1295
+ variant: mode === "destructive" ? "default" : "ghost",
1296
+ children: t("Rename / drop / change type…")
1297
+ }, void 0, false)]
1298
+ }, void 0, true), mode === "addTable" && /* @__PURE__ */ jsxDEV("div", {
1299
+ className: "mt-3 flex flex-wrap items-end gap-2",
1300
+ "data-testid": "sc-editor-table-form",
1301
+ children: [/* @__PURE__ */ jsxDEV("div", {
1302
+ className: "flex flex-col gap-1 text-xs",
1303
+ children: [/* @__PURE__ */ jsxDEV(Label, {
1304
+ htmlFor: "sc-editor-table-name",
1305
+ children: t("Table name")
1306
+ }, void 0, false), /* @__PURE__ */ jsxDEV(Input, {
1307
+ "data-testid": "sc-editor-table-name",
1308
+ id: "sc-editor-table-name",
1309
+ onChange: onTableNameChange,
1310
+ value: tableName
1311
+ }, void 0, false)]
1312
+ }, void 0, true), /* @__PURE__ */ jsxDEV(Button, {
1313
+ "data-testid": "sc-editor-table-apply",
1314
+ disabled: busy || tableName.trim() === "",
1315
+ onClick: onSubmitTable,
1316
+ size: "xs",
1317
+ type: "button",
1318
+ children: busy ? t("Applying…") : t("Apply")
1319
+ }, void 0, false), /* @__PURE__ */ jsxDEV(Button, {
1320
+ onClick: reset,
1321
+ size: "xs",
1322
+ type: "button",
1323
+ variant: "ghost",
1324
+ children: t("Cancel")
1325
+ }, void 0, false)]
1326
+ }, void 0, true), mode === "addColumn" && /* @__PURE__ */ jsxDEV("div", {
1327
+ className: "mt-3 flex flex-wrap items-end gap-2",
1328
+ "data-testid": "sc-editor-column-form",
1329
+ children: [/* @__PURE__ */ jsxDEV("div", {
1330
+ className: "flex flex-col gap-1 text-xs",
1331
+ children: [/* @__PURE__ */ jsxDEV(Label, {
1332
+ htmlFor: "sc-editor-column-table",
1333
+ children: t("Table name")
1334
+ }, void 0, false), /* @__PURE__ */ jsxDEV("select", {
1335
+ className: "h-8 rounded-md border border-input bg-transparent px-2 text-xs",
1336
+ "data-testid": "sc-editor-column-table",
1337
+ id: "sc-editor-column-table",
1338
+ onChange: onTargetTableChange,
1339
+ value: targetTable,
1340
+ children: tableNames.map((name) => /* @__PURE__ */ jsxDEV("option", {
1341
+ value: name,
1342
+ children: name
1343
+ }, name, false))
1344
+ }, void 0, false)]
1345
+ }, void 0, true), /* @__PURE__ */ jsxDEV("div", {
1346
+ className: "flex flex-col gap-1 text-xs",
1347
+ children: [/* @__PURE__ */ jsxDEV(Label, {
1348
+ htmlFor: "sc-editor-column-name",
1349
+ children: t("Column name")
1350
+ }, void 0, false), /* @__PURE__ */ jsxDEV(Input, {
1351
+ "data-testid": "sc-editor-column-name",
1352
+ id: "sc-editor-column-name",
1353
+ onChange: onColumnNameChange,
1354
+ value: columnName
1355
+ }, void 0, false)]
1356
+ }, void 0, true), /* @__PURE__ */ jsxDEV("div", {
1357
+ className: "flex flex-col gap-1 text-xs",
1358
+ children: [/* @__PURE__ */ jsxDEV(Label, {
1359
+ htmlFor: "sc-editor-column-type",
1360
+ children: t("Column type")
1361
+ }, void 0, false), /* @__PURE__ */ jsxDEV("select", {
1362
+ className: "h-8 rounded-md border border-input bg-transparent px-2 text-xs",
1363
+ "data-testid": "sc-editor-column-type",
1364
+ id: "sc-editor-column-type",
1365
+ onChange: onValidatorChange,
1366
+ value: validator,
1367
+ children: COLUMN_TYPES.map((type) => /* @__PURE__ */ jsxDEV("option", {
1368
+ value: type.validator,
1369
+ children: type.label
1370
+ }, type.validator, false))
1371
+ }, void 0, false)]
1372
+ }, void 0, true), /* @__PURE__ */ jsxDEV("span", {
1373
+ className: "text-[11px] text-muted-foreground",
1374
+ children: t("Optional")
1375
+ }, void 0, false), /* @__PURE__ */ jsxDEV(Button, {
1376
+ "data-testid": "sc-editor-column-apply",
1377
+ disabled: busy || columnName.trim() === "" || targetTable === "",
1378
+ onClick: onSubmitColumn,
1379
+ size: "xs",
1380
+ type: "button",
1381
+ children: busy ? t("Applying…") : t("Apply")
1382
+ }, void 0, false), /* @__PURE__ */ jsxDEV(Button, {
1383
+ onClick: reset,
1384
+ size: "xs",
1385
+ type: "button",
1386
+ variant: "ghost",
1387
+ children: t("Cancel")
1388
+ }, void 0, false)]
1389
+ }, void 0, true), mode === "addIndex" && /* @__PURE__ */ jsxDEV("div", {
1390
+ className: "mt-3 flex flex-wrap items-end gap-2",
1391
+ "data-testid": "sc-editor-index-form",
1392
+ children: [/* @__PURE__ */ jsxDEV("div", {
1393
+ className: "flex flex-col gap-1 text-xs",
1394
+ children: [/* @__PURE__ */ jsxDEV(Label, {
1395
+ htmlFor: "sc-editor-index-table",
1396
+ children: t("Table name")
1397
+ }, void 0, false), /* @__PURE__ */ jsxDEV("select", {
1398
+ className: "h-8 rounded-md border border-input bg-transparent px-2 text-xs",
1399
+ "data-testid": "sc-editor-index-table",
1400
+ id: "sc-editor-index-table",
1401
+ onChange: onTargetTableChange,
1402
+ value: targetTable,
1403
+ children: tableNames.map((name_0) => /* @__PURE__ */ jsxDEV("option", {
1404
+ value: name_0,
1405
+ children: name_0
1406
+ }, name_0, false))
1407
+ }, void 0, false)]
1408
+ }, void 0, true), /* @__PURE__ */ jsxDEV("div", {
1409
+ className: "flex flex-col gap-1 text-xs",
1410
+ children: [/* @__PURE__ */ jsxDEV(Label, {
1411
+ htmlFor: "sc-editor-index-name",
1412
+ children: t("Index name")
1413
+ }, void 0, false), /* @__PURE__ */ jsxDEV(Input, {
1414
+ "data-testid": "sc-editor-index-name",
1415
+ id: "sc-editor-index-name",
1416
+ onChange: onIndexNameChange,
1417
+ value: indexName
1418
+ }, void 0, false)]
1419
+ }, void 0, true), /* @__PURE__ */ jsxDEV("div", {
1420
+ className: "flex flex-col gap-1 text-xs",
1421
+ children: [/* @__PURE__ */ jsxDEV(Label, {
1422
+ htmlFor: "sc-editor-index-fields",
1423
+ children: t("Index fields (comma-separated)")
1424
+ }, void 0, false), /* @__PURE__ */ jsxDEV(Input, {
1425
+ "data-testid": "sc-editor-index-fields",
1426
+ id: "sc-editor-index-fields",
1427
+ onChange: onIndexFieldsChange,
1428
+ value: indexFields
1429
+ }, void 0, false)]
1430
+ }, void 0, true), /* @__PURE__ */ jsxDEV(Label, {
1431
+ className: "flex items-center gap-1 text-xs",
1432
+ htmlFor: "sc-editor-index-unique",
1433
+ children: [/* @__PURE__ */ jsxDEV("input", {
1434
+ checked: unique,
1435
+ "data-testid": "sc-editor-index-unique",
1436
+ id: "sc-editor-index-unique",
1437
+ onChange: onUniqueChange,
1438
+ type: "checkbox"
1439
+ }, void 0, false), /* @__PURE__ */ jsxDEV("span", {
1440
+ className: "text-muted-foreground",
1441
+ children: t("Unique")
1442
+ }, void 0, false)]
1443
+ }, void 0, true), /* @__PURE__ */ jsxDEV(Button, {
1444
+ "data-testid": "sc-editor-index-apply",
1445
+ disabled: busy || indexName.trim() === "" || indexFields.trim() === "",
1446
+ onClick: onSubmitIndex,
1447
+ size: "xs",
1448
+ type: "button",
1449
+ children: busy ? t("Applying…") : t("Apply")
1450
+ }, void 0, false), /* @__PURE__ */ jsxDEV(Button, {
1451
+ onClick: reset,
1452
+ size: "xs",
1453
+ type: "button",
1454
+ variant: "ghost",
1455
+ children: t("Cancel")
1456
+ }, void 0, false)]
1457
+ }, void 0, true), result?.kind === "error" && /* @__PURE__ */ jsxDEV("p", {
1458
+ className: "mt-3 text-sm text-destructive",
1459
+ "data-testid": "sc-editor-error",
1460
+ role: "alert",
1461
+ children: result.message
1462
+ }, void 0, false), result?.kind === "needs-migration" && /* @__PURE__ */ jsxDEV("div", {
1463
+ className: "mt-3 flex flex-col gap-2",
1464
+ "data-testid": "sc-editor-needs-migration",
1465
+ children: [/* @__PURE__ */ jsxDEV("p", {
1466
+ className: "text-sm text-warning",
1467
+ role: "alert",
1468
+ children: t("This edit changes stored data and must go through a migration. Review the migration before applying.")
1469
+ }, void 0, false), /* @__PURE__ */ jsxDEV(Button, {
1470
+ className: "self-start",
1471
+ "data-testid": "sc-editor-open-migrations",
1472
+ onClick: onOpenMigrations,
1473
+ size: "xs",
1474
+ type: "button",
1475
+ variant: "outline",
1476
+ children: t("Open Migrations")
1477
+ }, void 0, false)]
1478
+ }, void 0, true), result?.kind === "ok" && result.diagnostics.length > 0 && /* @__PURE__ */ jsxDEV("div", {
1479
+ className: "mt-3 flex flex-col gap-1",
1480
+ "data-testid": "sc-editor-diagnostics",
1481
+ children: [/* @__PURE__ */ jsxDEV("p", {
1482
+ className: "text-sm text-destructive",
1483
+ role: "alert",
1484
+ children: t("Codegen reported diagnostics:")
1485
+ }, void 0, false), /* @__PURE__ */ jsxDEV("ul", {
1486
+ className: "flex flex-col gap-0.5",
1487
+ children: result.diagnostics.map((diagnostic) => /* @__PURE__ */ jsxDEV("li", {
1488
+ className: "font-mono text-[11px] text-destructive",
1489
+ children: diagnostic
1490
+ }, diagnostic, false))
1491
+ }, void 0, false)]
1492
+ }, void 0, true)]
1493
+ }, void 0, true)]
1494
+ }, void 0, true);
1495
+ };
1496
+
1497
+ const LIST_TABLES = adminRef(ADMIN_FUNCTIONS.listTables);
1498
+ const LIST_TABLE_INDEXES = adminRef(ADMIN_FUNCTIONS.listTableIndexes);
1499
+ const READ_TABLE_PAGE = adminRef(ADMIN_FUNCTIONS.readTablePage);
1500
+ const DESCRIBE_TABLES = adminRef(ADMIN_FUNCTIONS.describeTables);
1501
+ const EMPTY_COLUMNS = {};
1502
+ const EMPTY_COLUMN_NAMES = [];
1503
+ const EMPTY_COLUMN_META = [];
1504
+ const ChevronIcon = (t0) => {
1505
+ const $ = c(5);
1506
+ const {
1507
+ open
1508
+ } = t0;
1509
+ const t1 = open && "rotate-90";
1510
+ let t2;
1511
+ if ($[0] !== t1) {
1512
+ t2 = cn("size-3.5 shrink-0 text-muted-foreground transition-transform duration-150", t1);
1513
+ $[0] = t1;
1514
+ $[1] = t2;
1515
+ } else {
1516
+ t2 = $[1];
1517
+ }
1518
+ let t3;
1519
+ if ($[2] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
1520
+ t3 = /* @__PURE__ */ jsxDEV("path", {
1521
+ d: "m9 6 6 6-6 6"
1522
+ }, void 0, false);
1523
+ $[2] = t3;
1524
+ } else {
1525
+ t3 = $[2];
1526
+ }
1527
+ let t4;
1528
+ if ($[3] !== t2) {
1529
+ t4 = /* @__PURE__ */ jsxDEV("svg", {
1530
+ "aria-hidden": "true",
1531
+ className: t2,
1532
+ fill: "none",
1533
+ stroke: "currentColor",
1534
+ strokeLinecap: "round",
1535
+ strokeLinejoin: "round",
1536
+ strokeWidth: 1.8,
1537
+ viewBox: "0 0 24 24",
1538
+ children: t3
1539
+ }, void 0, false);
1540
+ $[3] = t2;
1541
+ $[4] = t4;
1542
+ } else {
1543
+ t4 = $[4];
1544
+ }
1545
+ return t4;
1546
+ };
1547
+ const TableEntry = (t0) => {
1548
+ const $ = c(20);
1549
+ const {
1550
+ children,
1551
+ expanded,
1552
+ name,
1553
+ onToggle,
1554
+ rowCount,
1555
+ rowTestId,
1556
+ toggleTestId
1557
+ } = t0;
1558
+ let t1;
1559
+ if ($[0] !== expanded) {
1560
+ t1 = /* @__PURE__ */ jsxDEV(ChevronIcon, {
1561
+ open: expanded
1562
+ }, void 0, false);
1563
+ $[0] = expanded;
1564
+ $[1] = t1;
1565
+ } else {
1566
+ t1 = $[1];
1567
+ }
1568
+ let t2;
1569
+ if ($[2] !== name) {
1570
+ t2 = /* @__PURE__ */ jsxDEV("span", {
1571
+ className: "truncate font-mono text-xs text-foreground",
1572
+ title: name,
1573
+ children: name
1574
+ }, void 0, false);
1575
+ $[2] = name;
1576
+ $[3] = t2;
1577
+ } else {
1578
+ t2 = $[3];
1579
+ }
1580
+ let t3;
1581
+ if ($[4] !== rowCount) {
1582
+ t3 = /* @__PURE__ */ jsxDEV("span", {
1583
+ className: "ms-auto shrink-0 text-xs text-muted-foreground tabular-nums",
1584
+ children: ["(", rowCount, ")"]
1585
+ }, void 0, true);
1586
+ $[4] = rowCount;
1587
+ $[5] = t3;
1588
+ } else {
1589
+ t3 = $[5];
1590
+ }
1591
+ let t4;
1592
+ if ($[6] !== expanded || $[7] !== onToggle || $[8] !== t1 || $[9] !== t2 || $[10] !== t3 || $[11] !== toggleTestId) {
1593
+ t4 = /* @__PURE__ */ jsxDEV("button", {
1594
+ "aria-expanded": expanded,
1595
+ className: "flex w-full items-center gap-2 px-3 py-2 text-start transition-colors hover:bg-muted/50 aria-expanded:bg-muted/40",
1596
+ "data-testid": toggleTestId,
1597
+ onClick: onToggle,
1598
+ type: "button",
1599
+ children: [t1, t2, " ", t3]
1600
+ }, void 0, true);
1601
+ $[6] = expanded;
1602
+ $[7] = onToggle;
1603
+ $[8] = t1;
1604
+ $[9] = t2;
1605
+ $[10] = t3;
1606
+ $[11] = toggleTestId;
1607
+ $[12] = t4;
1608
+ } else {
1609
+ t4 = $[12];
1610
+ }
1611
+ let t5;
1612
+ if ($[13] !== children || $[14] !== expanded) {
1613
+ t5 = expanded && /* @__PURE__ */ jsxDEV("div", {
1614
+ className: "px-3 pb-3 ps-8",
1615
+ children
1616
+ }, void 0, false);
1617
+ $[13] = children;
1618
+ $[14] = expanded;
1619
+ $[15] = t5;
1620
+ } else {
1621
+ t5 = $[15];
1622
+ }
1623
+ let t6;
1624
+ if ($[16] !== rowTestId || $[17] !== t4 || $[18] !== t5) {
1625
+ t6 = /* @__PURE__ */ jsxDEV("li", {
1626
+ className: "border-t border-border/60 first:border-t-0",
1627
+ "data-testid": rowTestId,
1628
+ children: [t4, t5]
1629
+ }, void 0, true);
1630
+ $[16] = rowTestId;
1631
+ $[17] = t4;
1632
+ $[18] = t5;
1633
+ $[19] = t6;
1634
+ } else {
1635
+ t6 = $[19];
1636
+ }
1637
+ return t6;
1638
+ };
1639
+ const ColumnChips = (t0) => {
1640
+ const $ = c(5);
1641
+ const {
1642
+ columns,
1643
+ testId
1644
+ } = t0;
1645
+ let t1;
1646
+ if ($[0] !== columns) {
1647
+ t1 = columns.map(_temp);
1648
+ $[0] = columns;
1649
+ $[1] = t1;
1650
+ } else {
1651
+ t1 = $[1];
1652
+ }
1653
+ let t2;
1654
+ if ($[2] !== t1 || $[3] !== testId) {
1655
+ t2 = /* @__PURE__ */ jsxDEV("ul", {
1656
+ className: "flex flex-wrap gap-1.5 pt-1",
1657
+ "data-testid": testId,
1658
+ children: t1
1659
+ }, void 0, false);
1660
+ $[2] = t1;
1661
+ $[3] = testId;
1662
+ $[4] = t2;
1663
+ } else {
1664
+ t2 = $[4];
1665
+ }
1666
+ return t2;
1667
+ };
1668
+ const IndexList = (t0) => {
1669
+ const $ = c(10);
1670
+ const {
1671
+ heading,
1672
+ indexes,
1673
+ testId
1674
+ } = t0;
1675
+ let t1;
1676
+ if ($[0] !== heading) {
1677
+ t1 = /* @__PURE__ */ jsxDEV("p", {
1678
+ className: "mb-1.5 font-mono text-[10px] tracking-wide text-muted-foreground uppercase",
1679
+ children: heading
1680
+ }, void 0, false);
1681
+ $[0] = heading;
1682
+ $[1] = t1;
1683
+ } else {
1684
+ t1 = $[1];
1685
+ }
1686
+ let t2;
1687
+ if ($[2] !== indexes) {
1688
+ t2 = indexes.map(_temp2);
1689
+ $[2] = indexes;
1690
+ $[3] = t2;
1691
+ } else {
1692
+ t2 = $[3];
1693
+ }
1694
+ let t3;
1695
+ if ($[4] !== t2 || $[5] !== testId) {
1696
+ t3 = /* @__PURE__ */ jsxDEV("ul", {
1697
+ className: "flex flex-col gap-1",
1698
+ "data-testid": testId,
1699
+ children: t2
1700
+ }, void 0, false);
1701
+ $[4] = t2;
1702
+ $[5] = testId;
1703
+ $[6] = t3;
1704
+ } else {
1705
+ t3 = $[6];
1706
+ }
1707
+ let t4;
1708
+ if ($[7] !== t1 || $[8] !== t3) {
1709
+ t4 = /* @__PURE__ */ jsxDEV("div", {
1710
+ className: "pt-3",
1711
+ children: [t1, t3]
1712
+ }, void 0, true);
1713
+ $[7] = t1;
1714
+ $[8] = t3;
1715
+ $[9] = t4;
1716
+ } else {
1717
+ t4 = $[9];
1718
+ }
1719
+ return t4;
1720
+ };
1721
+ const SchemaViewer = (t0) => {
1722
+ const $ = c(126);
1723
+ const {
1724
+ initialShardKey,
1725
+ initialTable,
1726
+ schemaEditable
1727
+ } = t0;
1728
+ const client = useLunora();
1729
+ const t = useT();
1730
+ const [view, setView] = useState("list");
1731
+ const [shardKey, setShardKey] = useState(initialShardKey ?? "");
1732
+ const [tableFilter, setTableFilter] = useState("");
1733
+ const [tables, setTables] = useState(null);
1734
+ const [error, setError] = useState(null);
1735
+ let t1;
1736
+ if ($[0] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
1737
+ t1 = {};
1738
+ $[0] = t1;
1739
+ } else {
1740
+ t1 = $[0];
1741
+ }
1742
+ const [columns, setColumns] = useState(t1);
1743
+ let t2;
1744
+ if ($[1] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
1745
+ t2 = {};
1746
+ $[1] = t2;
1747
+ } else {
1748
+ t2 = $[1];
1749
+ }
1750
+ const [indexes, setIndexes] = useState(t2);
1751
+ const [expanded, setExpanded] = useState(null);
1752
+ let t3;
1753
+ if ($[2] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
1754
+ t3 = {};
1755
+ $[2] = t3;
1756
+ } else {
1757
+ t3 = $[2];
1758
+ }
1759
+ const [shardColumns, setShardColumns] = useState(t3);
1760
+ let t4;
1761
+ if ($[3] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
1762
+ t4 = {};
1763
+ $[3] = t4;
1764
+ } else {
1765
+ t4 = $[3];
1766
+ }
1767
+ const [shardColumnsError, setShardColumnsError] = useState(t4);
1768
+ const [globalTables, setGlobalTables] = useState(null);
1769
+ const [globalError, setGlobalError] = useState(null);
1770
+ let t5;
1771
+ if ($[4] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
1772
+ t5 = {};
1773
+ $[4] = t5;
1774
+ } else {
1775
+ t5 = $[4];
1776
+ }
1777
+ const [globalColumns, setGlobalColumns] = useState(t5);
1778
+ const [globalExpanded, setGlobalExpanded] = useState(null);
1779
+ let t6;
1780
+ if ($[5] !== client) {
1781
+ t6 = async (shard) => {
1782
+ setError(null);
1783
+ try {
1784
+ const result = await client.query(LIST_TABLES, {}, callOptions(shard));
1785
+ recordShard(shard);
1786
+ setTables(result);
1787
+ setColumns({});
1788
+ setIndexes({});
1789
+ setExpanded(null);
1790
+ setShardColumns((previous) => Object.fromEntries(Object.entries(previous).filter((t82) => {
1791
+ const [cachedShard] = t82;
1792
+ return cachedShard !== shard;
1793
+ })));
1794
+ setShardColumnsError((previous_0) => Object.fromEntries(Object.entries(previous_0).filter((t92) => {
1795
+ const [cachedShard_0] = t92;
1796
+ return cachedShard_0 !== shard;
1797
+ })));
1798
+ } catch (t72) {
1799
+ const error_ = t72;
1800
+ setTables(null);
1801
+ setError(errorMessage(error_));
1802
+ }
1803
+ };
1804
+ $[5] = client;
1805
+ $[6] = t6;
1806
+ } else {
1807
+ t6 = $[6];
1808
+ }
1809
+ const refresh = t6;
1810
+ let t7;
1811
+ if ($[7] !== client) {
1812
+ t7 = async () => {
1813
+ setGlobalError(null);
1814
+ try {
1815
+ setGlobalTables(await client.listGlobalTables());
1816
+ } catch (t82) {
1817
+ const error__0 = t82;
1818
+ setGlobalTables(null);
1819
+ setGlobalError(errorMessage(error__0));
1820
+ }
1821
+ };
1822
+ $[7] = client;
1823
+ $[8] = t7;
1824
+ } else {
1825
+ t7 = $[8];
1826
+ }
1827
+ const refreshGlobal = t7;
1828
+ let t8;
1829
+ if ($[9] !== shardKey) {
1830
+ t8 = shardKey.trim();
1831
+ $[9] = shardKey;
1832
+ $[10] = t8;
1833
+ } else {
1834
+ t8 = $[10];
1835
+ }
1836
+ const debouncedShard = useDebounced(t8, 400);
1837
+ let t10;
1838
+ let t9;
1839
+ if ($[11] !== debouncedShard || $[12] !== refresh || $[13] !== refreshGlobal) {
1840
+ t9 = () => {
1841
+ fireAndForget(refresh(debouncedShard));
1842
+ fireAndForget(refreshGlobal());
1843
+ };
1844
+ t10 = [refresh, refreshGlobal, debouncedShard];
1845
+ $[11] = debouncedShard;
1846
+ $[12] = refresh;
1847
+ $[13] = refreshGlobal;
1848
+ $[14] = t10;
1849
+ $[15] = t9;
1850
+ } else {
1851
+ t10 = $[14];
1852
+ t9 = $[15];
1853
+ }
1854
+ useEffect(t9, t10);
1855
+ let t11;
1856
+ if ($[16] !== client || $[17] !== columns || $[18] !== expanded || $[19] !== shardKey) {
1857
+ t11 = async (table) => {
1858
+ if (expanded === table) {
1859
+ setExpanded(null);
1860
+ return;
1861
+ }
1862
+ setExpanded(table);
1863
+ const cacheKey = `${shardKey}:${table}`;
1864
+ if (columns[cacheKey] !== void 0) {
1865
+ return;
1866
+ }
1867
+ const [page, indexResult] = await Promise.allSettled([client.query(READ_TABLE_PAGE, {
1868
+ limit: 1,
1869
+ offset: 0,
1870
+ table
1871
+ }, callOptions(shardKey)), client.query(LIST_TABLE_INDEXES, {
1872
+ table
1873
+ }, callOptions(shardKey))]);
1874
+ if (page.status === "fulfilled") {
1875
+ setColumns((previous_1) => ({
1876
+ ...previous_1,
1877
+ [cacheKey]: page.value.columns
1878
+ }));
1879
+ } else {
1880
+ setError(errorMessage(page.reason));
1881
+ }
1882
+ if (indexResult.status === "fulfilled") {
1883
+ setIndexes((previous_2) => ({
1884
+ ...previous_2,
1885
+ [cacheKey]: indexResult.value.indexes
1886
+ }));
1887
+ }
1888
+ };
1889
+ $[16] = client;
1890
+ $[17] = columns;
1891
+ $[18] = expanded;
1892
+ $[19] = shardKey;
1893
+ $[20] = t11;
1894
+ } else {
1895
+ t11 = $[20];
1896
+ }
1897
+ const toggle = t11;
1898
+ let t12;
1899
+ if ($[21] !== client || $[22] !== globalColumns || $[23] !== globalExpanded) {
1900
+ t12 = async (table_0) => {
1901
+ if (globalExpanded === table_0) {
1902
+ setGlobalExpanded(null);
1903
+ return;
1904
+ }
1905
+ setGlobalExpanded(table_0);
1906
+ if (globalColumns[table_0] !== void 0) {
1907
+ return;
1908
+ }
1909
+ try {
1910
+ const page_0 = await client.readGlobalTablePage({
1911
+ limit: 1,
1912
+ offset: 0,
1913
+ table: table_0
1914
+ });
1915
+ setGlobalColumns((previous_3) => ({
1916
+ ...previous_3,
1917
+ [table_0]: page_0.columns
1918
+ }));
1919
+ } catch (t132) {
1920
+ const error__1 = t132;
1921
+ setGlobalError(errorMessage(error__1));
1922
+ }
1923
+ };
1924
+ $[21] = client;
1925
+ $[22] = globalColumns;
1926
+ $[23] = globalExpanded;
1927
+ $[24] = t12;
1928
+ } else {
1929
+ t12 = $[24];
1930
+ }
1931
+ const toggleGlobal = t12;
1932
+ const appliedTable = useRef(void 0);
1933
+ let t13;
1934
+ let t14;
1935
+ if ($[25] !== initialTable || $[26] !== tables || $[27] !== toggle) {
1936
+ t13 = () => {
1937
+ if (initialTable === void 0 || tables === null || appliedTable.current === initialTable) {
1938
+ return;
1939
+ }
1940
+ if (tables.some((table_1) => table_1.name === initialTable)) {
1941
+ appliedTable.current = initialTable;
1942
+ fireAndForget(toggle(initialTable));
1943
+ }
1944
+ };
1945
+ t14 = [initialTable, tables, toggle];
1946
+ $[25] = initialTable;
1947
+ $[26] = tables;
1948
+ $[27] = toggle;
1949
+ $[28] = t13;
1950
+ $[29] = t14;
1951
+ } else {
1952
+ t13 = $[28];
1953
+ t14 = $[29];
1954
+ }
1955
+ useEffect(t13, t14);
1956
+ let t15;
1957
+ if ($[30] !== client) {
1958
+ t15 = async (shard_0, shardNames, globalNames) => {
1959
+ const [described, globalPages] = await Promise.all([Promise.allSettled([client.query(DESCRIBE_TABLES, {
1960
+ tables: [...shardNames, ...globalNames]
1961
+ }, callOptions(shard_0))]), Promise.all(globalNames.map(async (table_2) => {
1962
+ const page_1 = await Promise.allSettled([client.readGlobalTablePage({
1963
+ limit: 1,
1964
+ offset: 0,
1965
+ table: table_2
1966
+ })]);
1967
+ const value = page_1[0].status === "fulfilled" ? page_1[0].value : void 0;
1968
+ return {
1969
+ columns: value?.columns ?? [],
1970
+ refs: value?.refs ?? {},
1971
+ table: table_2
1972
+ };
1973
+ }))]);
1974
+ const typedColumns = described[0].status === "fulfilled" ? described[0].value?.columnsByTable ?? {} : {};
1975
+ const columnsFailed = described[0].status === "rejected";
1976
+ const globalFallback = new Map(globalPages.map(_temp3));
1977
+ const resolved = [...shardNames, ...globalNames].map((table_4) => {
1978
+ const typed = typedColumns[table_4] ?? [];
1979
+ return [table_4, typed.length > 0 ? typed : globalFallback.get(table_4) ?? []];
1980
+ });
1981
+ setShardColumns((previous_4) => ({
1982
+ ...previous_4,
1983
+ [shard_0]: Object.fromEntries(resolved)
1984
+ }));
1985
+ setShardColumnsError((previous_5) => ({
1986
+ ...previous_5,
1987
+ [shard_0]: columnsFailed
1988
+ }));
1989
+ };
1990
+ $[30] = client;
1991
+ $[31] = t15;
1992
+ } else {
1993
+ t15 = $[31];
1994
+ }
1995
+ const probeSchema = t15;
1996
+ let t16;
1997
+ let t17;
1998
+ if ($[32] !== globalError || $[33] !== globalTables || $[34] !== probeSchema || $[35] !== shardColumns || $[36] !== shardKey || $[37] !== tables || $[38] !== view) {
1999
+ t16 = () => {
2000
+ if (view !== "graph" || tables === null || globalTables === null && globalError === null || shardColumns[shardKey] !== void 0) {
2001
+ return;
2002
+ }
2003
+ fireAndForget(probeSchema(shardKey, tables.map(_temp4), (globalTables ?? []).map(_temp5)));
2004
+ };
2005
+ t17 = [view, tables, globalTables, globalError, shardKey, shardColumns, probeSchema];
2006
+ $[32] = globalError;
2007
+ $[33] = globalTables;
2008
+ $[34] = probeSchema;
2009
+ $[35] = shardColumns;
2010
+ $[36] = shardKey;
2011
+ $[37] = tables;
2012
+ $[38] = view;
2013
+ $[39] = t16;
2014
+ $[40] = t17;
2015
+ } else {
2016
+ t16 = $[39];
2017
+ t17 = $[40];
2018
+ }
2019
+ useEffect(t16, t17);
2020
+ const columnsForShard = shardColumns[shardKey] ?? EMPTY_COLUMNS;
2021
+ let t18;
2022
+ if ($[41] !== columnsForShard || $[42] !== globalTables || $[43] !== tables) {
2023
+ let t192;
2024
+ if ($[45] !== columnsForShard) {
2025
+ t192 = (table_7) => ({
2026
+ columns: columnsForShard[table_7.name] ?? EMPTY_COLUMN_META,
2027
+ name: table_7.name,
2028
+ tier: "shard"
2029
+ });
2030
+ $[45] = columnsForShard;
2031
+ $[46] = t192;
2032
+ } else {
2033
+ t192 = $[46];
2034
+ }
2035
+ const shardOnes = (tables ?? []).map(t192);
2036
+ let t202;
2037
+ if ($[47] !== columnsForShard) {
2038
+ t202 = (table_8) => ({
2039
+ columns: columnsForShard[table_8.name] ?? EMPTY_COLUMN_META,
2040
+ name: table_8.name,
2041
+ tier: "global"
2042
+ });
2043
+ $[47] = columnsForShard;
2044
+ $[48] = t202;
2045
+ } else {
2046
+ t202 = $[48];
2047
+ }
2048
+ const globalOnes = (globalTables ?? []).map(t202);
2049
+ t18 = [...shardOnes, ...globalOnes];
2050
+ $[41] = columnsForShard;
2051
+ $[42] = globalTables;
2052
+ $[43] = tables;
2053
+ $[44] = t18;
2054
+ } else {
2055
+ t18 = $[44];
2056
+ }
2057
+ const diagramTables = t18;
2058
+ let t19;
2059
+ if ($[49] !== tableFilter || $[50] !== tables) {
2060
+ const needle = tableFilter.trim().toLowerCase();
2061
+ t19 = (tables ?? []).filter((table_9) => table_9.name.toLowerCase().includes(needle));
2062
+ $[49] = tableFilter;
2063
+ $[50] = tables;
2064
+ $[51] = t19;
2065
+ } else {
2066
+ t19 = $[51];
2067
+ }
2068
+ const filteredTables = t19;
2069
+ let t20;
2070
+ if ($[52] !== globalTables || $[53] !== tableFilter) {
2071
+ const needle_0 = tableFilter.trim().toLowerCase();
2072
+ t20 = (globalTables ?? []).filter((table_10) => table_10.name.toLowerCase().includes(needle_0));
2073
+ $[52] = globalTables;
2074
+ $[53] = tableFilter;
2075
+ $[54] = t20;
2076
+ } else {
2077
+ t20 = $[54];
2078
+ }
2079
+ const filteredGlobalTables = t20;
2080
+ let t21;
2081
+ if ($[55] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
2082
+ t21 = () => {
2083
+ setView("list");
2084
+ };
2085
+ $[55] = t21;
2086
+ } else {
2087
+ t21 = $[55];
2088
+ }
2089
+ const showList = t21;
2090
+ let t22;
2091
+ if ($[56] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
2092
+ t22 = () => {
2093
+ setView("graph");
2094
+ };
2095
+ $[56] = t22;
2096
+ } else {
2097
+ t22 = $[56];
2098
+ }
2099
+ const showGraph = t22;
2100
+ let t23;
2101
+ if ($[57] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
2102
+ t23 = (event) => {
2103
+ setTableFilter(event.target.value);
2104
+ };
2105
+ $[57] = t23;
2106
+ } else {
2107
+ t23 = $[57];
2108
+ }
2109
+ const onFilterChange = t23;
2110
+ let t24;
2111
+ if ($[58] !== refresh || $[59] !== shardKey) {
2112
+ t24 = (_tables) => {
2113
+ fireAndForget(refresh(shardKey));
2114
+ };
2115
+ $[58] = refresh;
2116
+ $[59] = shardKey;
2117
+ $[60] = t24;
2118
+ } else {
2119
+ t24 = $[60];
2120
+ }
2121
+ const onSchemaApplied = t24;
2122
+ let t25;
2123
+ if ($[61] !== tables) {
2124
+ t25 = tables ?? [];
2125
+ $[61] = tables;
2126
+ $[62] = t25;
2127
+ } else {
2128
+ t25 = $[62];
2129
+ }
2130
+ let t26;
2131
+ if ($[63] !== t25) {
2132
+ t26 = t25.map(_temp6);
2133
+ $[63] = t25;
2134
+ $[64] = t26;
2135
+ } else {
2136
+ t26 = $[64];
2137
+ }
2138
+ const shardTableNames = t26;
2139
+ let t27;
2140
+ if ($[65] !== shardKey) {
2141
+ t27 = /* @__PURE__ */ jsxDEV(ShardInput, {
2142
+ onChange: setShardKey,
2143
+ testId: "sc-shard-input",
2144
+ value: shardKey
2145
+ }, void 0, false);
2146
+ $[65] = shardKey;
2147
+ $[66] = t27;
2148
+ } else {
2149
+ t27 = $[66];
2150
+ }
2151
+ let t28;
2152
+ if ($[67] !== t) {
2153
+ t28 = t("Schema view");
2154
+ $[67] = t;
2155
+ $[68] = t28;
2156
+ } else {
2157
+ t28 = $[68];
2158
+ }
2159
+ const t29 = view === "list";
2160
+ const t30 = view === "list" ? "default" : "outline";
2161
+ let t31;
2162
+ if ($[69] !== t) {
2163
+ t31 = t("Table list");
2164
+ $[69] = t;
2165
+ $[70] = t31;
2166
+ } else {
2167
+ t31 = $[70];
2168
+ }
2169
+ let t32;
2170
+ if ($[71] !== t29 || $[72] !== t30 || $[73] !== t31) {
2171
+ t32 = /* @__PURE__ */ jsxDEV(Button, {
2172
+ "aria-pressed": t29,
2173
+ "data-testid": "sc-view-list",
2174
+ onClick: showList,
2175
+ size: "xs",
2176
+ type: "button",
2177
+ variant: t30,
2178
+ children: t31
2179
+ }, void 0, false);
2180
+ $[71] = t29;
2181
+ $[72] = t30;
2182
+ $[73] = t31;
2183
+ $[74] = t32;
2184
+ } else {
2185
+ t32 = $[74];
2186
+ }
2187
+ const t33 = view === "graph";
2188
+ const t34 = view === "graph" ? "default" : "outline";
2189
+ let t35;
2190
+ if ($[75] !== t) {
2191
+ t35 = t("Graph");
2192
+ $[75] = t;
2193
+ $[76] = t35;
2194
+ } else {
2195
+ t35 = $[76];
2196
+ }
2197
+ let t36;
2198
+ if ($[77] !== t33 || $[78] !== t34 || $[79] !== t35) {
2199
+ t36 = /* @__PURE__ */ jsxDEV(Button, {
2200
+ "aria-pressed": t33,
2201
+ "data-testid": "sc-view-graph",
2202
+ onClick: showGraph,
2203
+ size: "xs",
2204
+ type: "button",
2205
+ variant: t34,
2206
+ children: t35
2207
+ }, void 0, false);
2208
+ $[77] = t33;
2209
+ $[78] = t34;
2210
+ $[79] = t35;
2211
+ $[80] = t36;
2212
+ } else {
2213
+ t36 = $[80];
2214
+ }
2215
+ let t37;
2216
+ if ($[81] !== t28 || $[82] !== t32 || $[83] !== t36) {
2217
+ t37 = /* @__PURE__ */ jsxDEV("div", {
2218
+ "aria-label": t28,
2219
+ className: "flex gap-1.5",
2220
+ "data-testid": "sc-view-toggle",
2221
+ role: "group",
2222
+ children: [t32, t36]
2223
+ }, void 0, true);
2224
+ $[81] = t28;
2225
+ $[82] = t32;
2226
+ $[83] = t36;
2227
+ $[84] = t37;
2228
+ } else {
2229
+ t37 = $[84];
2230
+ }
2231
+ let t38;
2232
+ if ($[85] !== t27 || $[86] !== t37) {
2233
+ t38 = /* @__PURE__ */ jsxDEV("div", {
2234
+ className: "flex flex-wrap items-center gap-3",
2235
+ children: [t27, t37]
2236
+ }, void 0, true);
2237
+ $[85] = t27;
2238
+ $[86] = t37;
2239
+ $[87] = t38;
2240
+ } else {
2241
+ t38 = $[87];
2242
+ }
2243
+ let t39;
2244
+ if ($[88] !== onSchemaApplied || $[89] !== schemaEditable || $[90] !== shardTableNames) {
2245
+ t39 = schemaEditable === true && /* @__PURE__ */ jsxDEV(SchemaEditorOverlay, {
2246
+ onApplied: onSchemaApplied,
2247
+ tableNames: shardTableNames
2248
+ }, void 0, false);
2249
+ $[88] = onSchemaApplied;
2250
+ $[89] = schemaEditable;
2251
+ $[90] = shardTableNames;
2252
+ $[91] = t39;
2253
+ } else {
2254
+ t39 = $[91];
2255
+ }
2256
+ let t40;
2257
+ if ($[92] !== t || $[93] !== tableFilter || $[94] !== view) {
2258
+ t40 = view === "list" && /* @__PURE__ */ jsxDEV(Input, {
2259
+ "aria-label": t("Filter tables"),
2260
+ className: "h-8 max-w-xs",
2261
+ "data-testid": "sc-filter",
2262
+ onChange: onFilterChange,
2263
+ placeholder: t("Filter tables"),
2264
+ value: tableFilter
2265
+ }, void 0, false);
2266
+ $[92] = t;
2267
+ $[93] = tableFilter;
2268
+ $[94] = view;
2269
+ $[95] = t40;
2270
+ } else {
2271
+ t40 = $[95];
2272
+ }
2273
+ let t41;
2274
+ if ($[96] !== diagramTables || $[97] !== error || $[98] !== globalError || $[99] !== shardColumnsError || $[100] !== shardKey || $[101] !== view) {
2275
+ t41 = view === "graph" && /* @__PURE__ */ jsxDEV("div", {
2276
+ className: "flex flex-col gap-2",
2277
+ "data-testid": "sc-graph-view",
2278
+ children: [error !== null && /* @__PURE__ */ jsxDEV("p", {
2279
+ className: "text-sm text-destructive",
2280
+ "data-testid": "sc-error",
2281
+ role: "alert",
2282
+ children: error
2283
+ }, void 0, false), globalError !== null && /* @__PURE__ */ jsxDEV("p", {
2284
+ className: "text-sm text-destructive",
2285
+ "data-testid": "sc-global-error",
2286
+ role: "alert",
2287
+ children: globalError
2288
+ }, void 0, false), /* @__PURE__ */ jsxDEV(SchemaDiagram, {
2289
+ columnsError: shardColumnsError[shardKey] === true,
2290
+ tables: diagramTables,
2291
+ testIdPrefix: "sc-graph"
2292
+ }, void 0, false)]
2293
+ }, void 0, true);
2294
+ $[96] = diagramTables;
2295
+ $[97] = error;
2296
+ $[98] = globalError;
2297
+ $[99] = shardColumnsError;
2298
+ $[100] = shardKey;
2299
+ $[101] = view;
2300
+ $[102] = t41;
2301
+ } else {
2302
+ t41 = $[102];
2303
+ }
2304
+ let t42;
2305
+ if ($[103] !== columns || $[104] !== error || $[105] !== expanded || $[106] !== filteredGlobalTables || $[107] !== filteredTables || $[108] !== globalColumns || $[109] !== globalError || $[110] !== globalExpanded || $[111] !== globalTables || $[112] !== indexes || $[113] !== shardKey || $[114] !== t || $[115] !== tables || $[116] !== toggle || $[117] !== toggleGlobal || $[118] !== view) {
2306
+ t42 = view === "list" && /* @__PURE__ */ jsxDEV("div", {
2307
+ className: "flex flex-col gap-4",
2308
+ children: [/* @__PURE__ */ jsxDEV(Card, {
2309
+ "data-testid": "sc-shard-section",
2310
+ size: "sm",
2311
+ children: [/* @__PURE__ */ jsxDEV(CardHeader, {
2312
+ children: [/* @__PURE__ */ jsxDEV("div", {
2313
+ className: "flex items-center gap-2",
2314
+ children: [/* @__PURE__ */ jsxDEV(StorageTierBadge, {
2315
+ tier: "shard"
2316
+ }, void 0, false), /* @__PURE__ */ jsxDEV(CardTitle, {
2317
+ children: t("Shard tables")
2318
+ }, void 0, false), tables !== null && /* @__PURE__ */ jsxDEV(Badge, {
2319
+ className: "ms-auto tabular-nums",
2320
+ variant: "outline",
2321
+ children: filteredTables.length
2322
+ }, void 0, false)]
2323
+ }, void 0, true), /* @__PURE__ */ jsxDEV(CardDescription, {
2324
+ children: TIER_META.shard.hint
2325
+ }, void 0, false)]
2326
+ }, void 0, true), /* @__PURE__ */ jsxDEV(CardContent, {
2327
+ children: [error !== null && /* @__PURE__ */ jsxDEV("p", {
2328
+ className: "text-sm text-destructive",
2329
+ "data-testid": "sc-error",
2330
+ role: "alert",
2331
+ children: error
2332
+ }, void 0, false), tables !== null && tables.length === 0 && /* @__PURE__ */ jsxDEV("p", {
2333
+ className: "text-sm text-muted-foreground",
2334
+ "data-testid": "sc-empty",
2335
+ children: t("No tables in this shard.")
2336
+ }, void 0, false), tables !== null && tables.length > 0 && filteredTables.length === 0 && /* @__PURE__ */ jsxDEV("p", {
2337
+ className: "text-sm text-muted-foreground",
2338
+ "data-testid": "sc-no-match",
2339
+ children: t("No tables match your filter.")
2340
+ }, void 0, false), filteredTables.length > 0 && /* @__PURE__ */ jsxDEV("ul", {
2341
+ className: "-mx-3 overflow-hidden border-t border-border",
2342
+ "data-testid": "sc-table-list",
2343
+ children: filteredTables.map((table_12) => {
2344
+ const cacheKey_0 = `${shardKey}:${table_12.name}`;
2345
+ const tableIndexes = indexes[cacheKey_0] ?? [];
2346
+ return /* @__PURE__ */ jsxDEV(TableEntry, {
2347
+ expanded: expanded === table_12.name,
2348
+ name: table_12.name,
2349
+ onToggle: () => {
2350
+ fireAndForget(toggle(table_12.name));
2351
+ },
2352
+ rowCount: table_12.rowCount,
2353
+ rowTestId: `sc-table-${table_12.name}`,
2354
+ toggleTestId: `sc-toggle-${table_12.name}`,
2355
+ children: [/* @__PURE__ */ jsxDEV(ColumnChips, {
2356
+ columns: columns[cacheKey_0] ?? EMPTY_COLUMN_NAMES,
2357
+ testId: `sc-columns-${table_12.name}`
2358
+ }, void 0, false), tableIndexes.length > 0 && /* @__PURE__ */ jsxDEV(IndexList, {
2359
+ heading: t("Indexes"),
2360
+ indexes: tableIndexes,
2361
+ testId: `sc-indexes-${table_12.name}`
2362
+ }, void 0, false)]
2363
+ }, table_12.name, true);
2364
+ })
2365
+ }, void 0, false)]
2366
+ }, void 0, true)]
2367
+ }, void 0, true), /* @__PURE__ */ jsxDEV(Card, {
2368
+ "data-testid": "sc-global-section",
2369
+ size: "sm",
2370
+ children: [/* @__PURE__ */ jsxDEV(CardHeader, {
2371
+ children: [/* @__PURE__ */ jsxDEV("div", {
2372
+ className: "flex items-center gap-2",
2373
+ children: [/* @__PURE__ */ jsxDEV(StorageTierBadge, {
2374
+ tier: "global"
2375
+ }, void 0, false), /* @__PURE__ */ jsxDEV(CardTitle, {
2376
+ children: t("Global tables (D1)")
2377
+ }, void 0, false), globalTables !== null && /* @__PURE__ */ jsxDEV(Badge, {
2378
+ className: "ms-auto tabular-nums",
2379
+ variant: "outline",
2380
+ children: filteredGlobalTables.length
2381
+ }, void 0, false)]
2382
+ }, void 0, true), /* @__PURE__ */ jsxDEV(CardDescription, {
2383
+ children: TIER_META.global.hint
2384
+ }, void 0, false)]
2385
+ }, void 0, true), /* @__PURE__ */ jsxDEV(CardContent, {
2386
+ children: [globalError !== null && /* @__PURE__ */ jsxDEV("p", {
2387
+ className: "text-sm text-destructive",
2388
+ "data-testid": "sc-global-error",
2389
+ role: "alert",
2390
+ children: globalError
2391
+ }, void 0, false), globalTables !== null && globalTables.length === 0 && /* @__PURE__ */ jsxDEV(EmptyState, {
2392
+ description: TIER_META.global.hint,
2393
+ testId: "sc-global-empty",
2394
+ title: t("No global tables.")
2395
+ }, void 0, false), globalTables !== null && globalTables.length > 0 && filteredGlobalTables.length === 0 && /* @__PURE__ */ jsxDEV("p", {
2396
+ className: "text-sm text-muted-foreground",
2397
+ "data-testid": "sc-global-no-match",
2398
+ children: t("No tables match your filter.")
2399
+ }, void 0, false), filteredGlobalTables.length > 0 && /* @__PURE__ */ jsxDEV("ul", {
2400
+ className: "-mx-3 overflow-hidden border-t border-border",
2401
+ "data-testid": "sc-global-table-list",
2402
+ children: filteredGlobalTables.map((table_13) => /* @__PURE__ */ jsxDEV(TableEntry, {
2403
+ expanded: globalExpanded === table_13.name,
2404
+ name: table_13.name,
2405
+ onToggle: () => {
2406
+ fireAndForget(toggleGlobal(table_13.name));
2407
+ },
2408
+ rowCount: table_13.rowCount,
2409
+ rowTestId: `sc-global-table-${table_13.name}`,
2410
+ toggleTestId: `sc-global-toggle-${table_13.name}`,
2411
+ children: /* @__PURE__ */ jsxDEV(ColumnChips, {
2412
+ columns: globalColumns[table_13.name] ?? EMPTY_COLUMN_NAMES,
2413
+ testId: `sc-global-columns-${table_13.name}`
2414
+ }, void 0, false)
2415
+ }, table_13.name, false))
2416
+ }, void 0, false)]
2417
+ }, void 0, true)]
2418
+ }, void 0, true)]
2419
+ }, void 0, true);
2420
+ $[103] = columns;
2421
+ $[104] = error;
2422
+ $[105] = expanded;
2423
+ $[106] = filteredGlobalTables;
2424
+ $[107] = filteredTables;
2425
+ $[108] = globalColumns;
2426
+ $[109] = globalError;
2427
+ $[110] = globalExpanded;
2428
+ $[111] = globalTables;
2429
+ $[112] = indexes;
2430
+ $[113] = shardKey;
2431
+ $[114] = t;
2432
+ $[115] = tables;
2433
+ $[116] = toggle;
2434
+ $[117] = toggleGlobal;
2435
+ $[118] = view;
2436
+ $[119] = t42;
2437
+ } else {
2438
+ t42 = $[119];
2439
+ }
2440
+ let t43;
2441
+ if ($[120] !== t38 || $[121] !== t39 || $[122] !== t40 || $[123] !== t41 || $[124] !== t42) {
2442
+ t43 = /* @__PURE__ */ jsxDEV("div", {
2443
+ className: "flex flex-col gap-4",
2444
+ "data-testid": "lunora-schema",
2445
+ children: [t38, t39, t40, t41, t42]
2446
+ }, void 0, true);
2447
+ $[120] = t38;
2448
+ $[121] = t39;
2449
+ $[122] = t40;
2450
+ $[123] = t41;
2451
+ $[124] = t42;
2452
+ $[125] = t43;
2453
+ } else {
2454
+ t43 = $[125];
2455
+ }
2456
+ return t43;
2457
+ };
2458
+ function _temp(column) {
2459
+ return /* @__PURE__ */ jsxDEV("li", {
2460
+ className: "rounded bg-muted px-1.5 py-0.5 font-mono text-[11px] text-muted-foreground",
2461
+ children: column
2462
+ }, column, false);
2463
+ }
2464
+ function _temp2(index) {
2465
+ return /* @__PURE__ */ jsxDEV("li", {
2466
+ className: "flex flex-wrap items-center gap-1.5 text-xs",
2467
+ children: [/* @__PURE__ */ jsxDEV("span", {
2468
+ className: "font-mono",
2469
+ children: index.name
2470
+ }, void 0, false), /* @__PURE__ */ jsxDEV(Badge, {
2471
+ variant: "outline",
2472
+ children: index.type
2473
+ }, void 0, false), index.unique === true && /* @__PURE__ */ jsxDEV(Badge, {
2474
+ variant: "secondary",
2475
+ children: "unique"
2476
+ }, void 0, false), /* @__PURE__ */ jsxDEV("span", {
2477
+ className: "text-muted-foreground",
2478
+ children: index.fields.join(", ")
2479
+ }, void 0, false)]
2480
+ }, `${index.type}:${index.name}`, true);
2481
+ }
2482
+ function _temp3(t0) {
2483
+ const {
2484
+ columns: columnNames,
2485
+ refs,
2486
+ table: table_3
2487
+ } = t0;
2488
+ return [table_3, columnNames.map((name) => {
2489
+ const ref = refs[name];
2490
+ return ref === void 0 ? {
2491
+ name,
2492
+ optional: false,
2493
+ type: ""
2494
+ } : {
2495
+ name,
2496
+ optional: false,
2497
+ ref,
2498
+ type: "id"
2499
+ };
2500
+ })];
2501
+ }
2502
+ function _temp4(table_5) {
2503
+ return table_5.name;
2504
+ }
2505
+ function _temp5(table_6) {
2506
+ return table_6.name;
2507
+ }
2508
+ function _temp6(table_11) {
2509
+ return table_11.name;
2510
+ }
2511
+
2512
+ export { SchemaViewer };