@mdxui/do 2.1.1 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/README.md +253 -266
  2. package/dist/{agents-xcIn2dUB.d.ts → agents-2_r9e9i7.d.ts} +213 -2
  3. package/dist/app/index.d.ts +347 -0
  4. package/dist/app/index.js +13 -0
  5. package/dist/app/index.js.map +1 -0
  6. package/dist/chunk-4KXVN3EQ.js +56 -0
  7. package/dist/chunk-4KXVN3EQ.js.map +1 -0
  8. package/dist/chunk-5AWTQDRF.js +76 -0
  9. package/dist/chunk-5AWTQDRF.js.map +1 -0
  10. package/dist/chunk-EQVOEEQO.js +95 -0
  11. package/dist/chunk-EQVOEEQO.js.map +1 -0
  12. package/dist/chunk-FO3N7SXV.js +469 -0
  13. package/dist/chunk-FO3N7SXV.js.map +1 -0
  14. package/dist/chunk-IESVTECE.js +536 -0
  15. package/dist/chunk-IESVTECE.js.map +1 -0
  16. package/dist/chunk-JWKIONEO.js +234 -0
  17. package/dist/chunk-JWKIONEO.js.map +1 -0
  18. package/dist/chunk-NTSEARBC.js +715 -0
  19. package/dist/chunk-NTSEARBC.js.map +1 -0
  20. package/dist/chunk-OWEAW4U6.js +116 -0
  21. package/dist/chunk-OWEAW4U6.js.map +1 -0
  22. package/dist/chunk-VRLUXCLD.js +31 -0
  23. package/dist/chunk-VRLUXCLD.js.map +1 -0
  24. package/dist/chunk-Y52IEYVM.js +131 -0
  25. package/dist/chunk-Y52IEYVM.js.map +1 -0
  26. package/dist/chunk-YGIBMNRH.js +1991 -0
  27. package/dist/chunk-YGIBMNRH.js.map +1 -0
  28. package/dist/components/index.d.ts +1 -738
  29. package/dist/components/index.js +2 -6
  30. package/dist/config-CmZBQQaT.d.ts +122 -0
  31. package/dist/{do-CaQVueZw.d.ts → do-C-t9UgjT.d.ts} +31 -33
  32. package/dist/errors-B4Oyyj4Z.d.ts +346 -0
  33. package/dist/hooks/index.d.ts +428 -696
  34. package/dist/hooks/index.js +6 -4
  35. package/dist/hooks/things/index.d.ts +298 -0
  36. package/dist/hooks/things/index.js +8 -0
  37. package/dist/hooks/things/index.js.map +1 -0
  38. package/dist/index.d.ts +21 -1010
  39. package/dist/index.js +11 -839
  40. package/dist/index.js.map +1 -1
  41. package/dist/lib/index.d.ts +100 -0
  42. package/dist/lib/index.js +6 -0
  43. package/dist/lib/index.js.map +1 -0
  44. package/dist/providers/index.d.ts +244 -32
  45. package/dist/providers/index.js +3 -2
  46. package/dist/query-keys-BC901wog.d.ts +153 -0
  47. package/dist/schemas/index.d.ts +1 -1
  48. package/dist/schemas/index.js +2 -2
  49. package/dist/schemas/index.js.map +1 -1
  50. package/dist/{thing-DtI25yZh.d.ts → thing-BVhCTzOi.d.ts} +4 -4
  51. package/dist/types/index.d.ts +251 -216
  52. package/dist/types/index.js +1 -2
  53. package/dist/views/index.d.ts +131 -0
  54. package/dist/views/index.js +11 -0
  55. package/dist/views/index.js.map +1 -0
  56. package/package.json +39 -17
  57. package/dist/__test-utils__/index.d.ts +0 -399
  58. package/dist/__test-utils__/index.js +0 -34641
  59. package/dist/__test-utils__/index.js.map +0 -1
  60. package/dist/chunk-EEDMN7UF.js +0 -1351
  61. package/dist/chunk-EEDMN7UF.js.map +0 -1
  62. package/dist/chunk-G3PMV62Z.js +0 -33
  63. package/dist/chunk-G3PMV62Z.js.map +0 -1
  64. package/dist/chunk-NXPXL5NA.js +0 -3789
  65. package/dist/chunk-NXPXL5NA.js.map +0 -1
  66. package/dist/chunk-PC5FJY6M.js +0 -20
  67. package/dist/chunk-PC5FJY6M.js.map +0 -1
  68. package/dist/chunk-XF6LKY2M.js +0 -445
  69. package/dist/chunk-XF6LKY2M.js.map +0 -1
  70. package/dist/magic-string.es-J7BYFTTJ.js +0 -1307
  71. package/dist/magic-string.es-J7BYFTTJ.js.map +0 -1
@@ -0,0 +1,1991 @@
1
+ import { useNamespaces, useTypes } from './chunk-IESVTECE.js';
2
+ import { useCreateThing, useThings, useThing, useUpdateThing, useDeleteThing } from './chunk-JWKIONEO.js';
3
+ import { useDO } from './chunk-FO3N7SXV.js';
4
+ import { cn } from './chunk-Y52IEYVM.js';
5
+ import * as React4 from 'react';
6
+ import { parseQuery, applyQueryFilter, DataSidebar, DataSidebarTrigger, QuerySearch, ViewSwitcher, DataFilterPopover, DatabaseListView, DatabaseTableView, DatabaseCardView, DatabaseCodeView, applyFilters, useEditHistory, DatabaseSidebar, TableEditorToolbar, DatabaseGrid, QueryView, FormatView, ColumnEditorPanel, TableCreatorPanel, DocumentSidebar, DocumentViewToolbar, DocumentEditor, FunctionSidebar, FunctionViewToolbar, SDKEditor } from '@mdxui/admin';
7
+ export { DataFilterPopover, DataSidebar, DataSidebarTrigger, FILTER_OPERATOR_OPTIONS } from '@mdxui/admin';
8
+ import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, Label, Select, SelectTrigger, SelectValue, SelectContent, SelectItem, Input, Textarea, DialogFooter, Button, Sheet, SheetContent, SheetHeader, SheetTitle, SheetDescription, Badge, ScrollArea, SheetFooter, Tooltip, TooltipTrigger, TooltipContent, TooltipProvider, AlertDialog, AlertDialogTrigger, AlertDialogContent, AlertDialogHeader, AlertDialogTitle, AlertDialogDescription, AlertDialogFooter, AlertDialogCancel, AlertDialogAction, DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuCheckboxItem, DropdownMenuItem, Toaster } from '@mdxui/primitives';
9
+ import { Hash, Save, Pencil, Copy, X, Trash2, Columns3, Plus, MoreVertical, Download, RefreshCw, Database, ExternalLink, Calendar, Clock } from 'lucide-react';
10
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
11
+ import { toast } from 'sonner';
12
+
13
+ function CreateDialog({
14
+ open,
15
+ onOpenChange,
16
+ namespace,
17
+ defaultType,
18
+ types,
19
+ onCreated
20
+ }) {
21
+ const [selectedType, setSelectedType] = React4.useState(defaultType ?? "");
22
+ const [name, setName] = React4.useState("");
23
+ const [dataJson, setDataJson] = React4.useState("{}");
24
+ const [jsonError, setJsonError] = React4.useState(null);
25
+ const createMutation = useCreateThing();
26
+ React4.useEffect(() => {
27
+ if (open) {
28
+ setSelectedType(defaultType ?? "");
29
+ setName("");
30
+ setDataJson("{}");
31
+ setJsonError(null);
32
+ }
33
+ }, [open, defaultType]);
34
+ const handleSubmit = async (e) => {
35
+ e.preventDefault();
36
+ setJsonError(null);
37
+ let parsedData;
38
+ try {
39
+ parsedData = JSON.parse(dataJson);
40
+ } catch {
41
+ setJsonError("Invalid JSON format");
42
+ return;
43
+ }
44
+ try {
45
+ const result = await createMutation.mutateAsync({
46
+ ns: namespace,
47
+ type: selectedType,
48
+ name: name.trim(),
49
+ data: parsedData
50
+ });
51
+ onCreated?.(result);
52
+ onOpenChange(false);
53
+ } catch (error) {
54
+ console.error("Failed to create thing:", error);
55
+ }
56
+ };
57
+ return /* @__PURE__ */ jsx(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxs(DialogContent, { children: [
58
+ /* @__PURE__ */ jsxs(DialogHeader, { children: [
59
+ /* @__PURE__ */ jsx(DialogTitle, { children: "Create New Thing" }),
60
+ /* @__PURE__ */ jsxs(DialogDescription, { children: [
61
+ 'Create a new thing in namespace "',
62
+ namespace,
63
+ '"'
64
+ ] })
65
+ ] }),
66
+ /* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit, className: "space-y-4", children: [
67
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
68
+ /* @__PURE__ */ jsx(Label, { htmlFor: "type", children: "Type" }),
69
+ /* @__PURE__ */ jsxs(Select, { value: selectedType, onValueChange: setSelectedType, children: [
70
+ /* @__PURE__ */ jsx(SelectTrigger, { children: /* @__PURE__ */ jsx(SelectValue, { placeholder: "Select a type" }) }),
71
+ /* @__PURE__ */ jsx(SelectContent, { children: types.map((type) => /* @__PURE__ */ jsx(SelectItem, { value: type.name, children: type.label }, type.id)) })
72
+ ] })
73
+ ] }),
74
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
75
+ /* @__PURE__ */ jsx(Label, { htmlFor: "name", children: "Name" }),
76
+ /* @__PURE__ */ jsx(
77
+ Input,
78
+ {
79
+ id: "name",
80
+ value: name,
81
+ onChange: (e) => setName(e.target.value),
82
+ placeholder: "Enter a name",
83
+ required: true
84
+ }
85
+ )
86
+ ] }),
87
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
88
+ /* @__PURE__ */ jsx(Label, { htmlFor: "data", children: "Data (JSON)" }),
89
+ /* @__PURE__ */ jsx(
90
+ Textarea,
91
+ {
92
+ id: "data",
93
+ value: dataJson,
94
+ onChange: (e) => {
95
+ setDataJson(e.target.value);
96
+ setJsonError(null);
97
+ },
98
+ placeholder: '{"key": "value"}',
99
+ className: "font-mono text-sm min-h-[100px]"
100
+ }
101
+ ),
102
+ jsonError && /* @__PURE__ */ jsx("p", { className: "text-sm text-destructive", children: jsonError })
103
+ ] }),
104
+ /* @__PURE__ */ jsxs(DialogFooter, { children: [
105
+ /* @__PURE__ */ jsx(Button, { type: "button", variant: "outline", onClick: () => onOpenChange(false), children: "Cancel" }),
106
+ /* @__PURE__ */ jsx(
107
+ Button,
108
+ {
109
+ type: "submit",
110
+ disabled: !selectedType || !name.trim() || createMutation.isLoading,
111
+ children: createMutation.isLoading ? "Creating..." : "Create"
112
+ }
113
+ )
114
+ ] })
115
+ ] })
116
+ ] }) });
117
+ }
118
+
119
+ // src/views/utils/date-formatting.ts
120
+ function isISODateString(value) {
121
+ if (typeof value !== "string") return false;
122
+ const date = new Date(value);
123
+ return !isNaN(date.getTime()) && value.includes("T");
124
+ }
125
+ function formatDate(dateValue) {
126
+ const date = typeof dateValue === "string" ? new Date(dateValue) : dateValue;
127
+ const now = /* @__PURE__ */ new Date();
128
+ const diffMs = now.getTime() - date.getTime();
129
+ const diffMins = Math.floor(diffMs / 6e4);
130
+ const diffHours = Math.floor(diffMins / 60);
131
+ const diffDays = Math.floor(diffHours / 24);
132
+ let relative;
133
+ if (diffMins < 1) relative = "Just now";
134
+ else if (diffMins < 60) relative = `${diffMins} minute${diffMins !== 1 ? "s" : ""} ago`;
135
+ else if (diffHours < 24) relative = `${diffHours} hour${diffHours !== 1 ? "s" : ""} ago`;
136
+ else if (diffDays < 7) relative = `${diffDays} day${diffDays !== 1 ? "s" : ""} ago`;
137
+ else
138
+ relative = date.toLocaleDateString("en-US", {
139
+ month: "short",
140
+ day: "numeric",
141
+ year: "numeric"
142
+ });
143
+ return {
144
+ date: date.toLocaleDateString("en-US", {
145
+ weekday: "short",
146
+ month: "short",
147
+ day: "numeric",
148
+ year: "numeric"
149
+ }),
150
+ time: date.toLocaleTimeString("en-US", {
151
+ hour: "2-digit",
152
+ minute: "2-digit"
153
+ }),
154
+ relative
155
+ };
156
+ }
157
+ function formatFieldName(key) {
158
+ return key.replace(/([A-Z])/g, " $1").replace(/_/g, " ").replace(/^./, (str) => str.toUpperCase()).trim();
159
+ }
160
+
161
+ // src/views/utils/export.ts
162
+ function exportToJSON(data, filename) {
163
+ const json = JSON.stringify(data, null, 2);
164
+ const blob = new Blob([json], { type: "application/json" });
165
+ const url = URL.createObjectURL(blob);
166
+ const link = document.createElement("a");
167
+ link.href = url;
168
+ link.download = `${filename}.json`;
169
+ document.body.appendChild(link);
170
+ link.click();
171
+ document.body.removeChild(link);
172
+ URL.revokeObjectURL(url);
173
+ }
174
+ function DetailSheet({ open, onOpenChange, thing, onEdit, onSave }) {
175
+ const [isEditing, setIsEditing] = React4.useState(false);
176
+ const [editedName, setEditedName] = React4.useState("");
177
+ const [editedDataJson, setEditedDataJson] = React4.useState("");
178
+ const [jsonError, setJsonError] = React4.useState(null);
179
+ const [isSaving, setIsSaving] = React4.useState(false);
180
+ React4.useEffect(() => {
181
+ if (thing && open) {
182
+ setEditedName(thing.name);
183
+ setEditedDataJson(JSON.stringify(thing.data ?? {}, null, 2));
184
+ setJsonError(null);
185
+ }
186
+ if (!open) {
187
+ setIsEditing(false);
188
+ }
189
+ }, [thing, open]);
190
+ const handleStartEdit = () => {
191
+ if (thing) {
192
+ setEditedName(thing.name);
193
+ setEditedDataJson(JSON.stringify(thing.data ?? {}, null, 2));
194
+ setJsonError(null);
195
+ setIsEditing(true);
196
+ }
197
+ };
198
+ const handleCancelEdit = () => {
199
+ if (thing) {
200
+ setEditedName(thing.name);
201
+ setEditedDataJson(JSON.stringify(thing.data ?? {}, null, 2));
202
+ setJsonError(null);
203
+ }
204
+ setIsEditing(false);
205
+ };
206
+ const handleSave = async () => {
207
+ if (!thing || !onSave) return;
208
+ setJsonError(null);
209
+ let parsedData;
210
+ try {
211
+ parsedData = JSON.parse(editedDataJson);
212
+ } catch {
213
+ setJsonError("Invalid JSON format");
214
+ return;
215
+ }
216
+ const updates = {};
217
+ if (editedName !== thing.name) {
218
+ updates.name = editedName;
219
+ }
220
+ if (JSON.stringify(parsedData) !== JSON.stringify(thing.data)) {
221
+ updates.data = parsedData;
222
+ }
223
+ if (Object.keys(updates).length === 0) {
224
+ setIsEditing(false);
225
+ return;
226
+ }
227
+ setIsSaving(true);
228
+ try {
229
+ await onSave(thing, updates);
230
+ setIsEditing(false);
231
+ } catch (error) {
232
+ console.error("Failed to save:", error);
233
+ } finally {
234
+ setIsSaving(false);
235
+ }
236
+ };
237
+ if (!thing) return null;
238
+ const renderValue = (_key, value) => {
239
+ if (value === null || value === void 0) {
240
+ return /* @__PURE__ */ jsx("span", { className: "text-muted-foreground italic text-sm", children: "null" });
241
+ }
242
+ if (typeof value === "boolean") {
243
+ return /* @__PURE__ */ jsx(Badge, { variant: value ? "default" : "secondary", children: value ? "Yes" : "No" });
244
+ }
245
+ if (Array.isArray(value)) {
246
+ return /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1.5", children: value.map((v, i) => /* @__PURE__ */ jsx(Badge, { variant: "outline", className: "text-xs font-normal", children: String(v) }, String(i))) });
247
+ }
248
+ if (typeof value === "object") {
249
+ return /* @__PURE__ */ jsx("pre", { className: "text-xs bg-muted/50 p-3 rounded-[var(--radius)] overflow-auto max-h-48 font-mono", children: JSON.stringify(value, null, 2) });
250
+ }
251
+ if (typeof value === "string" && (value.startsWith("http://") || value.startsWith("https://"))) {
252
+ return /* @__PURE__ */ jsxs(
253
+ "a",
254
+ {
255
+ href: value,
256
+ target: "_blank",
257
+ rel: "noopener noreferrer",
258
+ className: "text-primary hover:underline inline-flex items-center gap-1.5 break-all",
259
+ children: [
260
+ value,
261
+ /* @__PURE__ */ jsx(ExternalLink, { className: "h-3 w-3 shrink-0" })
262
+ ]
263
+ }
264
+ );
265
+ }
266
+ if (typeof value === "string" && isISODateString(value)) {
267
+ const formatted = formatDate(value);
268
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-0.5", children: [
269
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-sm", children: [
270
+ /* @__PURE__ */ jsx(Calendar, { className: "h-3.5 w-3.5 text-muted-foreground" }),
271
+ /* @__PURE__ */ jsx("span", { children: formatted.date })
272
+ ] }),
273
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-sm text-muted-foreground", children: [
274
+ /* @__PURE__ */ jsx(Clock, { className: "h-3.5 w-3.5" }),
275
+ /* @__PURE__ */ jsx("span", { children: formatted.time }),
276
+ /* @__PURE__ */ jsxs("span", { className: "text-xs", children: [
277
+ "(",
278
+ formatted.relative,
279
+ ")"
280
+ ] })
281
+ ] })
282
+ ] });
283
+ }
284
+ if (value instanceof Date) {
285
+ const formatted = formatDate(value);
286
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-0.5", children: [
287
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-sm", children: [
288
+ /* @__PURE__ */ jsx(Calendar, { className: "h-3.5 w-3.5 text-muted-foreground" }),
289
+ /* @__PURE__ */ jsx("span", { children: formatted.date })
290
+ ] }),
291
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-sm text-muted-foreground", children: [
292
+ /* @__PURE__ */ jsx(Clock, { className: "h-3.5 w-3.5" }),
293
+ /* @__PURE__ */ jsx("span", { children: formatted.time }),
294
+ /* @__PURE__ */ jsxs("span", { className: "text-xs", children: [
295
+ "(",
296
+ formatted.relative,
297
+ ")"
298
+ ] })
299
+ ] })
300
+ ] });
301
+ }
302
+ if (typeof value === "number") {
303
+ return /* @__PURE__ */ jsx("span", { className: "tabular-nums", children: value.toLocaleString() });
304
+ }
305
+ return /* @__PURE__ */ jsx("span", { className: "break-all", children: String(value) });
306
+ };
307
+ return /* @__PURE__ */ jsx(Sheet, { open, onOpenChange, children: /* @__PURE__ */ jsxs(SheetContent, { className: "sm:max-w-lg flex flex-col p-0", children: [
308
+ /* @__PURE__ */ jsx(SheetHeader, { className: "px-6 py-4 border-b bg-muted/30", children: /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-4 pr-8", children: [
309
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1 min-w-0", children: [
310
+ isEditing ? /* @__PURE__ */ jsx(
311
+ Input,
312
+ {
313
+ value: editedName,
314
+ onChange: (e) => setEditedName(e.target.value),
315
+ className: "text-lg font-semibold h-auto py-1"
316
+ }
317
+ ) : /* @__PURE__ */ jsx(SheetTitle, { className: "text-lg truncate", children: thing.name }),
318
+ /* @__PURE__ */ jsxs(SheetDescription, { className: "flex items-center gap-2", children: [
319
+ /* @__PURE__ */ jsx(Hash, { className: "h-3.5 w-3.5" }),
320
+ /* @__PURE__ */ jsx("span", { className: "font-mono text-xs", children: thing.id })
321
+ ] })
322
+ ] }),
323
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
324
+ isEditing && /* @__PURE__ */ jsx(Badge, { variant: "secondary", className: "shrink-0", children: "Editing" }),
325
+ /* @__PURE__ */ jsx(Badge, { variant: "outline", className: "capitalize shrink-0", children: thing.type })
326
+ ] })
327
+ ] }) }),
328
+ /* @__PURE__ */ jsx(ScrollArea, { className: "flex-1", children: /* @__PURE__ */ jsxs("div", { className: "p-4 space-y-4", children: [
329
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5 py-2", children: [
330
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-muted-foreground uppercase tracking-wider", children: "Namespace" }),
331
+ renderValue("ns", thing.ns)
332
+ ] }),
333
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5 py-2", children: [
334
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-muted-foreground uppercase tracking-wider", children: "Type" }),
335
+ renderValue("type", thing.type)
336
+ ] }),
337
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5 py-2", children: [
338
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-muted-foreground uppercase tracking-wider", children: "Created" }),
339
+ renderValue("createdAt", thing.createdAt)
340
+ ] }),
341
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5 py-2", children: [
342
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-muted-foreground uppercase tracking-wider", children: "Updated" }),
343
+ renderValue("updatedAt", thing.updatedAt)
344
+ ] }),
345
+ isEditing ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5 py-2", children: [
346
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-muted-foreground uppercase tracking-wider", children: "Data (JSON)" }),
347
+ /* @__PURE__ */ jsx(
348
+ Textarea,
349
+ {
350
+ value: editedDataJson,
351
+ onChange: (e) => {
352
+ setEditedDataJson(e.target.value);
353
+ setJsonError(null);
354
+ },
355
+ className: "font-mono text-sm min-h-[200px]"
356
+ }
357
+ ),
358
+ jsonError && /* @__PURE__ */ jsx("p", { className: "text-sm text-destructive", children: jsonError })
359
+ ] }) : thing.data && Object.entries(thing.data).filter(([key]) => !key.startsWith("@")).map(([key, value]) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1.5 py-2", children: [
360
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-medium text-muted-foreground uppercase tracking-wider", children: formatFieldName(key) }),
361
+ renderValue(key, value)
362
+ ] }, key))
363
+ ] }) }),
364
+ /* @__PURE__ */ jsx(SheetFooter, { className: "border-t px-6 py-4 bg-muted/30", children: /* @__PURE__ */ jsx("div", { className: "flex w-full items-center justify-between gap-3", children: isEditing ? /* @__PURE__ */ jsxs(Fragment, { children: [
365
+ /* @__PURE__ */ jsx(Button, { variant: "outline", size: "sm", onClick: handleCancelEdit, disabled: isSaving, children: "Cancel" }),
366
+ /* @__PURE__ */ jsx(
367
+ Button,
368
+ {
369
+ size: "sm",
370
+ onClick: handleSave,
371
+ disabled: isSaving || !editedName.trim(),
372
+ className: "gap-2",
373
+ children: isSaving ? /* @__PURE__ */ jsx(Fragment, { children: "Saving..." }) : /* @__PURE__ */ jsxs(Fragment, { children: [
374
+ /* @__PURE__ */ jsx(Save, { className: "h-4 w-4" }),
375
+ "Save"
376
+ ] })
377
+ }
378
+ )
379
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
380
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
381
+ onSave && /* @__PURE__ */ jsxs(
382
+ Button,
383
+ {
384
+ variant: "outline",
385
+ size: "sm",
386
+ className: "gap-2",
387
+ onClick: handleStartEdit,
388
+ children: [
389
+ /* @__PURE__ */ jsx(Pencil, { className: "h-4 w-4" }),
390
+ "Edit"
391
+ ]
392
+ }
393
+ ),
394
+ onEdit && !onSave && /* @__PURE__ */ jsxs(
395
+ Button,
396
+ {
397
+ variant: "outline",
398
+ size: "sm",
399
+ className: "gap-2",
400
+ onClick: () => onEdit(thing),
401
+ children: [
402
+ /* @__PURE__ */ jsx(Pencil, { className: "h-4 w-4" }),
403
+ "Edit"
404
+ ]
405
+ }
406
+ ),
407
+ /* @__PURE__ */ jsxs(Tooltip, { children: [
408
+ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
409
+ Button,
410
+ {
411
+ variant: "outline",
412
+ size: "sm",
413
+ onClick: () => {
414
+ navigator.clipboard.writeText(JSON.stringify(thing, null, 2));
415
+ },
416
+ children: /* @__PURE__ */ jsx(Copy, { className: "h-4 w-4" })
417
+ }
418
+ ) }),
419
+ /* @__PURE__ */ jsx(TooltipContent, { children: "Copy as JSON" })
420
+ ] })
421
+ ] }),
422
+ /* @__PURE__ */ jsx(Button, { variant: "secondary", size: "sm", onClick: () => onOpenChange(false), children: "Close" })
423
+ ] }) }) })
424
+ ] }) });
425
+ }
426
+ function getTableColumns() {
427
+ return [
428
+ { accessorKey: "name", header: "Name", type: "text" },
429
+ { accessorKey: "type", header: "Type", type: "text" },
430
+ { accessorKey: "createdAt", header: "Created", type: "date" },
431
+ { accessorKey: "updatedAt", header: "Updated", type: "date" }
432
+ ];
433
+ }
434
+ function DataBrowserView({
435
+ initialNamespace,
436
+ initialType,
437
+ onSelect,
438
+ onOpen,
439
+ className
440
+ }) {
441
+ const { namespace: contextNamespace, client } = useDO();
442
+ const [selectedNamespace, setSelectedNamespace] = React4.useState(
443
+ initialNamespace ?? contextNamespace
444
+ );
445
+ const [selectedType, setSelectedType] = React4.useState(
446
+ initialType
447
+ );
448
+ const [viewType, setViewType] = React4.useState("table");
449
+ const [searchQuery, setSearchQuery] = React4.useState("");
450
+ const [selectedIds, setSelectedIds] = React4.useState([]);
451
+ const [sidebarCollapsed, setSidebarCollapsed] = React4.useState(false);
452
+ const [detailThing, setDetailThing] = React4.useState(null);
453
+ const [detailOpen, setDetailOpen] = React4.useState(false);
454
+ const [recentQueries, setRecentQueries] = React4.useState([]);
455
+ const [createDialogOpen, setCreateDialogOpen] = React4.useState(false);
456
+ const [filterPopoverOpen, setFilterPopoverOpen] = React4.useState(false);
457
+ const [filterConditions, setFilterConditions] = React4.useState([]);
458
+ const [hiddenColumns, setHiddenColumns] = React4.useState(
459
+ /* @__PURE__ */ new Set()
460
+ );
461
+ const { data: namespaces, error: namespacesError } = useNamespaces();
462
+ const { data: types, error: typesError } = useTypes({ ns: selectedNamespace });
463
+ const filter = React4.useMemo(() => {
464
+ const f = { ns: selectedNamespace };
465
+ if (selectedType) f.type = selectedType;
466
+ if (searchQuery) f.nameSearch = searchQuery;
467
+ return f;
468
+ }, [selectedNamespace, selectedType, searchQuery]);
469
+ const { data: thingsResult, isLoading, error: thingsError, refetch } = useThings(filter);
470
+ const connectionError = namespacesError || typesError || thingsError;
471
+ const queryConditions = React4.useMemo(() => {
472
+ return parseQuery(searchQuery);
473
+ }, [searchQuery]);
474
+ const data = React4.useMemo(() => {
475
+ if (!thingsResult?.data) return [];
476
+ let filtered = thingsResult.data.map((thing) => ({
477
+ id: thing.id,
478
+ ns: thing.ns,
479
+ type: thing.type,
480
+ name: thing.name,
481
+ createdAt: thing.createdAt,
482
+ updatedAt: thing.updatedAt,
483
+ ...thing.data
484
+ }));
485
+ if (queryConditions.length > 0) {
486
+ filtered = applyQueryFilter(filtered, queryConditions);
487
+ }
488
+ if (filterConditions.length > 0) {
489
+ filtered = filtered.filter((item) => {
490
+ return filterConditions.every((condition) => {
491
+ const fieldValue = item[condition.field];
492
+ const strValue = String(fieldValue ?? "").toLowerCase();
493
+ const conditionValue = condition.value.toLowerCase();
494
+ switch (condition.operator) {
495
+ case "equals":
496
+ return strValue === conditionValue;
497
+ case "contains":
498
+ return strValue.includes(conditionValue);
499
+ case "startsWith":
500
+ return strValue.startsWith(conditionValue);
501
+ case "endsWith":
502
+ return strValue.endsWith(conditionValue);
503
+ case "isEmpty":
504
+ return !fieldValue || strValue === "";
505
+ case "isNotEmpty":
506
+ return !!fieldValue && strValue !== "";
507
+ default:
508
+ return true;
509
+ }
510
+ });
511
+ });
512
+ }
513
+ return filtered;
514
+ }, [thingsResult, queryConditions, filterConditions]);
515
+ const allTableColumns = React4.useMemo(() => getTableColumns(), []);
516
+ const tableColumns = React4.useMemo(
517
+ () => allTableColumns.filter((col) => !hiddenColumns.has(col.accessorKey)),
518
+ [allTableColumns, hiddenColumns]
519
+ );
520
+ const queryFields = React4.useMemo(() => {
521
+ return ["name", "type", "ns", "createdAt", "updatedAt"];
522
+ }, []);
523
+ const handleExportSelected = React4.useCallback(() => {
524
+ if (selectedIds.length === 0) return;
525
+ const exportData = data.filter((d) => selectedIds.includes(d.id));
526
+ const filename = `${selectedNamespace}-${selectedType ?? "all"}-selected-${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}`;
527
+ exportToJSON(exportData, filename);
528
+ }, [data, selectedIds, selectedNamespace, selectedType]);
529
+ const handleExportAll = React4.useCallback(() => {
530
+ const filename = `${selectedNamespace}-${selectedType ?? "all"}-${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}`;
531
+ exportToJSON(data, filename);
532
+ }, [data, selectedNamespace, selectedType]);
533
+ const handleSaveThing = React4.useCallback(
534
+ async (thing, updates) => {
535
+ await client.Thing.update({
536
+ ns: thing.ns,
537
+ type: thing.type,
538
+ id: thing.id,
539
+ ...updates
540
+ });
541
+ await refetch();
542
+ if (detailThing?.id === thing.id) {
543
+ const updated = thingsResult?.data?.find((t) => t.id === thing.id);
544
+ if (updated) {
545
+ setDetailThing(updated);
546
+ }
547
+ }
548
+ },
549
+ [client, refetch, detailThing, thingsResult]
550
+ );
551
+ const handleItemClick = React4.useCallback(
552
+ (item) => {
553
+ const thing = thingsResult?.data?.find((t) => t.id === item.id);
554
+ if (thing) {
555
+ setDetailThing(thing);
556
+ setDetailOpen(true);
557
+ onSelect?.(thing);
558
+ }
559
+ },
560
+ [thingsResult, onSelect]
561
+ );
562
+ const handleClearSelection = React4.useCallback(() => {
563
+ setSelectedIds([]);
564
+ }, []);
565
+ const handleSelectRecentQuery = React4.useCallback((query) => {
566
+ setRecentQueries((prev) => {
567
+ const filtered = prev.filter((q) => q !== query);
568
+ return [query, ...filtered].slice(0, 10);
569
+ });
570
+ setSearchQuery(query);
571
+ }, []);
572
+ React4.useEffect(() => {
573
+ const mediaQuery = window.matchMedia("(max-width: 768px)");
574
+ const handleMediaChange = (e) => {
575
+ if (e.matches) {
576
+ setSidebarCollapsed(true);
577
+ }
578
+ };
579
+ handleMediaChange(mediaQuery);
580
+ mediaQuery.addEventListener("change", handleMediaChange);
581
+ return () => mediaQuery.removeEventListener("change", handleMediaChange);
582
+ }, []);
583
+ return /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsxs("div", { className: cn("flex h-full bg-background", className), children: [
584
+ /* @__PURE__ */ jsx(
585
+ DataSidebar,
586
+ {
587
+ title: "Types",
588
+ items: types?.map((t) => ({ id: t.id, name: t.name, label: t.label })),
589
+ selectedItem: selectedType,
590
+ onSelectItem: setSelectedType,
591
+ collapsed: sidebarCollapsed,
592
+ onCollapsedChange: setSidebarCollapsed,
593
+ allItemsLabel: "All Types",
594
+ emptyMessage: "No types found"
595
+ }
596
+ ),
597
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-1 flex-col overflow-hidden", children: [
598
+ /* @__PURE__ */ jsxs("header", { className: "flex h-12 shrink-0 items-center gap-3 border-b px-4", children: [
599
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 shrink-0", children: [
600
+ /* @__PURE__ */ jsx(
601
+ DataSidebarTrigger,
602
+ {
603
+ collapsed: sidebarCollapsed,
604
+ onToggle: () => setSidebarCollapsed(!sidebarCollapsed)
605
+ }
606
+ ),
607
+ /* @__PURE__ */ jsx(
608
+ "select",
609
+ {
610
+ value: selectedNamespace,
611
+ onChange: (e) => {
612
+ setSelectedNamespace(e.target.value);
613
+ setSelectedType(void 0);
614
+ },
615
+ className: "h-8 rounded-md border border-input bg-background px-2 text-sm",
616
+ children: namespaces?.map((ns) => /* @__PURE__ */ jsx("option", { value: ns.name, children: ns.name }, ns.id))
617
+ }
618
+ ),
619
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "/" }),
620
+ /* @__PURE__ */ jsx("span", { className: "font-medium text-sm", children: selectedType ?? "All Types" })
621
+ ] }),
622
+ /* @__PURE__ */ jsx("div", { className: "hidden sm:flex flex-1" }),
623
+ /* @__PURE__ */ jsx(
624
+ QuerySearch,
625
+ {
626
+ query: searchQuery,
627
+ onQueryChange: setSearchQuery,
628
+ conditions: queryConditions,
629
+ fields: queryFields,
630
+ recentQueries,
631
+ onSelectRecentQuery: handleSelectRecentQuery,
632
+ placeholder: "Search... (e.g., type: User)",
633
+ className: "flex-1 min-w-0 sm:w-64 sm:flex-none md:w-80 lg:w-[480px]"
634
+ }
635
+ ),
636
+ /* @__PURE__ */ jsx("div", { className: "hidden sm:flex flex-1" }),
637
+ selectedIds.length > 0 && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 animate-in fade-in-0 slide-in-from-left-2 duration-200 shrink-0", children: [
638
+ /* @__PURE__ */ jsxs(Badge, { variant: "secondary", className: "gap-1 pl-2 pr-1", children: [
639
+ /* @__PURE__ */ jsx("span", { className: "tabular-nums", children: selectedIds.length }),
640
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "selected" }),
641
+ /* @__PURE__ */ jsx(
642
+ "button",
643
+ {
644
+ type: "button",
645
+ onClick: handleClearSelection,
646
+ className: "ml-0.5 rounded-sm p-0.5 hover:bg-muted-foreground/20 transition-colors",
647
+ children: /* @__PURE__ */ jsx(X, { className: "h-3 w-3" })
648
+ }
649
+ )
650
+ ] }),
651
+ /* @__PURE__ */ jsxs(AlertDialog, { children: [
652
+ /* @__PURE__ */ jsxs(Tooltip, { children: [
653
+ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(AlertDialogTrigger, { asChild: true, children: /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "icon", className: "h-7 w-7", children: /* @__PURE__ */ jsx(Trash2, { className: "h-4 w-4 text-destructive" }) }) }) }),
654
+ /* @__PURE__ */ jsx(TooltipContent, { children: "Delete selected" })
655
+ ] }),
656
+ /* @__PURE__ */ jsxs(AlertDialogContent, { children: [
657
+ /* @__PURE__ */ jsxs(AlertDialogHeader, { children: [
658
+ /* @__PURE__ */ jsxs(AlertDialogTitle, { children: [
659
+ "Delete ",
660
+ selectedIds.length,
661
+ " item",
662
+ selectedIds.length !== 1 ? "s" : "",
663
+ "?"
664
+ ] }),
665
+ /* @__PURE__ */ jsx(AlertDialogDescription, { children: "This action cannot be undone. The selected items will be permanently removed." })
666
+ ] }),
667
+ /* @__PURE__ */ jsxs(AlertDialogFooter, { children: [
668
+ /* @__PURE__ */ jsx(AlertDialogCancel, { children: "Cancel" }),
669
+ /* @__PURE__ */ jsx(
670
+ AlertDialogAction,
671
+ {
672
+ className: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
673
+ onClick: async () => {
674
+ try {
675
+ const thingsToDelete = thingsResult?.data?.filter(
676
+ (t) => selectedIds.includes(t.id)
677
+ ) ?? [];
678
+ await Promise.all(
679
+ thingsToDelete.map(
680
+ (thing) => client.Thing.delete({
681
+ ns: thing.ns,
682
+ type: thing.type,
683
+ id: thing.id
684
+ })
685
+ )
686
+ );
687
+ setSelectedIds([]);
688
+ await refetch();
689
+ } catch (err) {
690
+ console.error("Failed to delete:", err);
691
+ }
692
+ },
693
+ children: "Delete"
694
+ }
695
+ )
696
+ ] })
697
+ ] })
698
+ ] })
699
+ ] }),
700
+ /* @__PURE__ */ jsx(
701
+ ViewSwitcher,
702
+ {
703
+ currentView: viewType,
704
+ onViewChange: setViewType,
705
+ availableViews: ["list", "table", "card", "code"],
706
+ className: "hidden sm:inline-flex"
707
+ }
708
+ ),
709
+ /* @__PURE__ */ jsx("div", { className: "hidden sm:block h-4 w-px bg-border" }),
710
+ /* @__PURE__ */ jsx(
711
+ DataFilterPopover,
712
+ {
713
+ open: filterPopoverOpen,
714
+ onOpenChange: setFilterPopoverOpen,
715
+ conditions: filterConditions,
716
+ onConditionsChange: setFilterConditions,
717
+ availableFields: queryFields
718
+ }
719
+ ),
720
+ viewType === "table" && /* @__PURE__ */ jsxs(DropdownMenu, { children: [
721
+ /* @__PURE__ */ jsxs(Tooltip, { children: [
722
+ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
723
+ Button,
724
+ {
725
+ variant: "ghost",
726
+ size: "icon",
727
+ className: "h-7 w-7 relative",
728
+ children: [
729
+ /* @__PURE__ */ jsx(Columns3, { className: "h-4 w-4" }),
730
+ hiddenColumns.size > 0 && /* @__PURE__ */ jsx("span", { className: "absolute -right-1 -top-1 flex h-4 w-4 items-center justify-center rounded-full bg-primary text-[10px] text-primary-foreground", children: hiddenColumns.size })
731
+ ]
732
+ }
733
+ ) }) }),
734
+ /* @__PURE__ */ jsx(TooltipContent, { children: "Columns" })
735
+ ] }),
736
+ /* @__PURE__ */ jsxs(DropdownMenuContent, { align: "end", className: "w-48", children: [
737
+ /* @__PURE__ */ jsx(DropdownMenuLabel, { children: "Toggle columns" }),
738
+ /* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
739
+ allTableColumns.map((column) => /* @__PURE__ */ jsx(
740
+ DropdownMenuCheckboxItem,
741
+ {
742
+ checked: !hiddenColumns.has(column.accessorKey),
743
+ onCheckedChange: (checked) => {
744
+ setHiddenColumns((prev) => {
745
+ const next = new Set(prev);
746
+ if (checked) {
747
+ next.delete(column.accessorKey);
748
+ } else {
749
+ next.add(column.accessorKey);
750
+ }
751
+ return next;
752
+ });
753
+ },
754
+ children: column.header
755
+ },
756
+ column.accessorKey
757
+ ))
758
+ ] })
759
+ ] }),
760
+ /* @__PURE__ */ jsxs(
761
+ Button,
762
+ {
763
+ variant: "default",
764
+ size: "sm",
765
+ className: "gap-1.5 px-3 hidden sm:inline-flex",
766
+ onClick: () => setCreateDialogOpen(true),
767
+ children: [
768
+ /* @__PURE__ */ jsx(Plus, { className: "h-4 w-4" }),
769
+ /* @__PURE__ */ jsx("span", { children: "Add" })
770
+ ]
771
+ }
772
+ ),
773
+ /* @__PURE__ */ jsxs(DropdownMenu, { children: [
774
+ /* @__PURE__ */ jsxs(Tooltip, { children: [
775
+ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "icon", className: "h-7 w-7", children: /* @__PURE__ */ jsx(MoreVertical, { className: "h-4 w-4" }) }) }) }),
776
+ /* @__PURE__ */ jsx(TooltipContent, { children: "More actions" })
777
+ ] }),
778
+ /* @__PURE__ */ jsxs(DropdownMenuContent, { align: "end", children: [
779
+ /* @__PURE__ */ jsxs(
780
+ DropdownMenuItem,
781
+ {
782
+ disabled: selectedIds.length === 0,
783
+ onClick: handleExportSelected,
784
+ children: [
785
+ /* @__PURE__ */ jsx(Download, { className: "h-4 w-4 mr-2" }),
786
+ "Export selected (",
787
+ selectedIds.length,
788
+ ")"
789
+ ]
790
+ }
791
+ ),
792
+ /* @__PURE__ */ jsxs(DropdownMenuItem, { onClick: handleExportAll, children: [
793
+ /* @__PURE__ */ jsx(Download, { className: "h-4 w-4 mr-2" }),
794
+ "Export all (",
795
+ data.length,
796
+ ")"
797
+ ] }),
798
+ /* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
799
+ /* @__PURE__ */ jsxs(DropdownMenuItem, { onClick: () => refetch(), children: [
800
+ /* @__PURE__ */ jsx(RefreshCw, { className: "h-4 w-4 mr-2" }),
801
+ "Refresh data"
802
+ ] })
803
+ ] })
804
+ ] })
805
+ ] }),
806
+ /* @__PURE__ */ jsx("div", { className: "flex min-h-0 flex-1 flex-col overflow-hidden p-2", children: connectionError ? /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center h-full", children: /* @__PURE__ */ jsxs("div", { className: "text-center max-w-md p-6", children: [
807
+ /* @__PURE__ */ jsx("div", { className: "mx-auto mb-4 h-12 w-12 rounded-full bg-destructive/10 flex items-center justify-center", children: /* @__PURE__ */ jsx(X, { className: "h-6 w-6 text-destructive" }) }),
808
+ /* @__PURE__ */ jsx("h3", { className: "font-semibold text-lg mb-2", children: "Connection Error" }),
809
+ /* @__PURE__ */ jsx("p", { className: "text-muted-foreground text-sm mb-4", children: connectionError.message }),
810
+ /* @__PURE__ */ jsxs(
811
+ Button,
812
+ {
813
+ variant: "outline",
814
+ size: "sm",
815
+ onClick: () => refetch(),
816
+ className: "gap-2",
817
+ children: [
818
+ /* @__PURE__ */ jsx(RefreshCw, { className: "h-4 w-4" }),
819
+ "Retry"
820
+ ]
821
+ }
822
+ )
823
+ ] }) }) : isLoading ? /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center h-full", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-2", children: [
824
+ /* @__PURE__ */ jsx("div", { className: "h-8 w-8 animate-spin rounded-full border-4 border-primary border-t-transparent" }),
825
+ /* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: "Loading..." })
826
+ ] }) }) : data.length === 0 ? /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center h-full", children: /* @__PURE__ */ jsxs("div", { className: "text-center", children: [
827
+ /* @__PURE__ */ jsx("p", { className: "text-muted-foreground", children: "No things found" }),
828
+ searchQuery && /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground mt-1", children: "Try adjusting your search query" })
829
+ ] }) }) : /* @__PURE__ */ jsxs(Fragment, { children: [
830
+ viewType === "list" && /* @__PURE__ */ jsx(
831
+ DatabaseListView,
832
+ {
833
+ data,
834
+ displayFields: ["name", "type", "ns"],
835
+ primaryField: "name",
836
+ secondaryField: "type",
837
+ selectedIds,
838
+ onSelectionChange: setSelectedIds,
839
+ onRecordClick: handleItemClick
840
+ }
841
+ ),
842
+ viewType === "table" && /* @__PURE__ */ jsx(
843
+ DatabaseTableView,
844
+ {
845
+ data,
846
+ columns: tableColumns,
847
+ onSelectionChange: setSelectedIds,
848
+ onRowClick: handleItemClick,
849
+ enableRowSelection: true,
850
+ enablePagination: false,
851
+ enableColumnVisibility: false
852
+ }
853
+ ),
854
+ viewType === "card" && /* @__PURE__ */ jsx("div", { className: "h-full overflow-auto p-2", children: /* @__PURE__ */ jsx(
855
+ DatabaseCardView,
856
+ {
857
+ data,
858
+ titleField: "name",
859
+ descriptionField: "type",
860
+ badgeFields: ["ns"],
861
+ onItemClick: handleItemClick,
862
+ columns: 3
863
+ }
864
+ ) }),
865
+ viewType === "code" && /* @__PURE__ */ jsx(DatabaseCodeView, { data, height: "100%", format: "json" })
866
+ ] }) }),
867
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-4 py-2 border-t border-border bg-muted/50 text-sm text-muted-foreground", children: [
868
+ /* @__PURE__ */ jsxs("span", { children: [
869
+ thingsResult?.total ?? 0,
870
+ " items",
871
+ selectedType && ` \u2022 Type: ${selectedType}`
872
+ ] }),
873
+ /* @__PURE__ */ jsxs("span", { children: [
874
+ "Page ",
875
+ thingsResult?.page ?? 1,
876
+ " of ",
877
+ thingsResult?.totalPages ?? 1
878
+ ] })
879
+ ] })
880
+ ] }),
881
+ /* @__PURE__ */ jsx(
882
+ DetailSheet,
883
+ {
884
+ open: detailOpen,
885
+ onOpenChange: setDetailOpen,
886
+ thing: detailThing,
887
+ onEdit: onOpen,
888
+ onSave: handleSaveThing
889
+ }
890
+ ),
891
+ /* @__PURE__ */ jsx(
892
+ CreateDialog,
893
+ {
894
+ open: createDialogOpen,
895
+ onOpenChange: setCreateDialogOpen,
896
+ namespace: selectedNamespace,
897
+ defaultType: selectedType,
898
+ types: types ?? [],
899
+ onCreated: (thing) => {
900
+ refetch();
901
+ setDetailThing(thing);
902
+ setDetailOpen(true);
903
+ }
904
+ }
905
+ )
906
+ ] }) });
907
+ }
908
+ function inferDataType(value) {
909
+ if (value === null || value === void 0) return "text";
910
+ if (typeof value === "boolean") return "boolean";
911
+ if (typeof value === "number") return "number";
912
+ if (value instanceof Date) return "date";
913
+ if (typeof value === "string") {
914
+ if (/^\d{4}-\d{2}-\d{2}/.test(value)) return "date";
915
+ if (value.includes("@")) return "email";
916
+ }
917
+ if (typeof value === "object") return "json";
918
+ return "text";
919
+ }
920
+ function generateColumns(things) {
921
+ const columns = [
922
+ { accessorKey: "id", header: "ID", dataType: "text", isPrimaryKey: true, editable: false },
923
+ { accessorKey: "name", header: "Name", dataType: "text" },
924
+ { accessorKey: "createdAt", header: "Created", dataType: "date", editable: false },
925
+ { accessorKey: "updatedAt", header: "Updated", dataType: "date", editable: false }
926
+ ];
927
+ const dataKeys = /* @__PURE__ */ new Map();
928
+ things.forEach((thing) => {
929
+ if (thing.data && typeof thing.data === "object") {
930
+ Object.entries(thing.data).forEach(([key, value]) => {
931
+ if (!key.startsWith("@") && !dataKeys.has(key)) {
932
+ dataKeys.set(key, inferDataType(value));
933
+ }
934
+ });
935
+ }
936
+ });
937
+ dataKeys.forEach((dataType, key) => {
938
+ columns.push({
939
+ accessorKey: key,
940
+ header: key.charAt(0).toUpperCase() + key.slice(1),
941
+ dataType
942
+ });
943
+ });
944
+ return columns;
945
+ }
946
+ function thingToRow(thing) {
947
+ return {
948
+ id: thing.id,
949
+ _ns: thing.ns,
950
+ _type: thing.type,
951
+ name: thing.name,
952
+ createdAt: thing.createdAt,
953
+ updatedAt: thing.updatedAt,
954
+ ...thing.data
955
+ };
956
+ }
957
+ function DataGridView({
958
+ initialNamespace,
959
+ initialType,
960
+ readOnly = false,
961
+ onRowSelect: _onRowSelect,
962
+ className
963
+ }) {
964
+ const { namespace: contextNamespace, client } = useDO();
965
+ const [selectedNamespace, setSelectedNamespace] = React4.useState(
966
+ initialNamespace ?? contextNamespace
967
+ );
968
+ const [selectedType, setSelectedType] = React4.useState(initialType);
969
+ const [selectedTable, setSelectedTable] = React4.useState(
970
+ `${selectedNamespace}.${initialType ?? ""}`
971
+ );
972
+ const [sidebarCollapsed, setSidebarCollapsed] = React4.useState(false);
973
+ const [viewMode, setViewMode] = React4.useState("table");
974
+ const [formatViewFormat, _setFormatViewFormat] = React4.useState("json");
975
+ const [selectedRows, setSelectedRows] = React4.useState([]);
976
+ const [filters, setFilters] = React4.useState([]);
977
+ const [hiddenColumns, setHiddenColumns] = React4.useState(/* @__PURE__ */ new Set());
978
+ const [refreshStatus, setRefreshStatus] = React4.useState("idle");
979
+ const [autoRefreshEnabled, setAutoRefreshEnabled] = React4.useState(false);
980
+ const [autoRefreshInterval, setAutoRefreshInterval] = React4.useState(30);
981
+ const [lastRefreshTime, setLastRefreshTime] = React4.useState(null);
982
+ const [columnEditorOpen, setColumnEditorOpen] = React4.useState(false);
983
+ const [tableCreatorOpen, setTableCreatorOpen] = React4.useState(false);
984
+ const [editingColumn, setEditingColumn] = React4.useState();
985
+ const gridActionsRef = React4.useRef(null);
986
+ const [localData, setLocalData] = React4.useState([]);
987
+ const { data: namespaces } = useNamespaces();
988
+ const { data: types } = useTypes({ ns: selectedNamespace });
989
+ const filter = React4.useMemo(() => {
990
+ const f = { ns: selectedNamespace };
991
+ if (selectedType) f.type = selectedType;
992
+ return f;
993
+ }, [selectedNamespace, selectedType]);
994
+ const { data: thingsResult, isLoading, refetch } = useThings(filter);
995
+ React4.useEffect(() => {
996
+ if (thingsResult?.data) {
997
+ setLocalData(thingsResult.data.map(thingToRow));
998
+ }
999
+ }, [thingsResult]);
1000
+ const schemas = React4.useMemo(() => {
1001
+ if (!namespaces || !types) return [];
1002
+ return namespaces.map((ns) => ({
1003
+ name: ns.name,
1004
+ tables: types.filter((t) => t.namespace === ns.name).map((t) => ({
1005
+ name: t.name,
1006
+ schema: ns.name,
1007
+ rowCount: 0
1008
+ // We don't have row counts per type from the hook
1009
+ }))
1010
+ }));
1011
+ }, [namespaces, types]);
1012
+ const columns = React4.useMemo(() => {
1013
+ if (!thingsResult?.data || thingsResult.data.length === 0) {
1014
+ return [
1015
+ { accessorKey: "id", header: "ID", dataType: "text", isPrimaryKey: true, editable: false },
1016
+ { accessorKey: "name", header: "Name", dataType: "text" },
1017
+ { accessorKey: "createdAt", header: "Created", dataType: "date" },
1018
+ { accessorKey: "updatedAt", header: "Updated", dataType: "date" }
1019
+ ];
1020
+ }
1021
+ return generateColumns(thingsResult.data);
1022
+ }, [thingsResult]);
1023
+ const visibleColumns = React4.useMemo(
1024
+ () => columns.filter((col) => !hiddenColumns.has(col.accessorKey)),
1025
+ [columns, hiddenColumns]
1026
+ );
1027
+ const filteredData = React4.useMemo(
1028
+ () => applyFilters(localData, filters, columns),
1029
+ [localData, filters, columns]
1030
+ );
1031
+ const {
1032
+ pushOperation,
1033
+ undo,
1034
+ redo,
1035
+ canUndo,
1036
+ canRedo,
1037
+ undoCount,
1038
+ redoCount
1039
+ } = useEditHistory({
1040
+ onRedo: (operation) => {
1041
+ const { rowIndex, columnId, newValue } = operation;
1042
+ setLocalData((prev) => {
1043
+ const newData = [...prev];
1044
+ newData[rowIndex] = { ...newData[rowIndex], [columnId]: newValue };
1045
+ return newData;
1046
+ });
1047
+ },
1048
+ onUndo: (operation) => {
1049
+ const { rowIndex, columnId, oldValue } = operation;
1050
+ setLocalData((prev) => {
1051
+ const newData = [...prev];
1052
+ newData[rowIndex] = { ...newData[rowIndex], [columnId]: oldValue };
1053
+ return newData;
1054
+ });
1055
+ }
1056
+ });
1057
+ const handleSelectTable = React4.useCallback((schema2, table) => {
1058
+ setSelectedNamespace(schema2);
1059
+ setSelectedType(table);
1060
+ setSelectedTable(`${schema2}.${table}`);
1061
+ setSelectedRows([]);
1062
+ setFilters([]);
1063
+ }, []);
1064
+ const handleAddColumn = React4.useCallback(() => {
1065
+ setEditingColumn(void 0);
1066
+ setColumnEditorOpen(true);
1067
+ }, []);
1068
+ const handleSaveColumn = React4.useCallback(
1069
+ async (column) => {
1070
+ if (!selectedType) return;
1071
+ try {
1072
+ const nullable = column.isNullable ? "" : "NOT NULL";
1073
+ const defaultVal = column.defaultValue ? `DEFAULT ${column.isDefaultExpression ? column.defaultValue : `'${column.defaultValue}'`}` : "";
1074
+ const unique = column.isUnique ? "UNIQUE" : "";
1075
+ const sql = editingColumn ? `ALTER TABLE ${selectedType} RENAME COLUMN ${editingColumn.name} TO ${column.name}` : `ALTER TABLE ${selectedType} ADD COLUMN ${column.name} ${column.dataType} ${nullable} ${defaultVal} ${unique}`;
1076
+ await client.SQL.execute({ query: sql.trim() });
1077
+ setColumnEditorOpen(false);
1078
+ toast.success(`Column "${column.name}" ${editingColumn ? "updated" : "created"}`);
1079
+ await refetch();
1080
+ } catch (err) {
1081
+ toast.error(`Failed to save column: ${err instanceof Error ? err.message : "Unknown error"}`);
1082
+ }
1083
+ },
1084
+ [selectedType, editingColumn, client, refetch]
1085
+ );
1086
+ const handleDeleteColumn = React4.useCallback(async () => {
1087
+ if (!selectedType || !editingColumn) return;
1088
+ try {
1089
+ await client.SQL.execute({
1090
+ query: `ALTER TABLE ${selectedType} DROP COLUMN ${editingColumn.name}`
1091
+ });
1092
+ setColumnEditorOpen(false);
1093
+ toast.success(`Column "${editingColumn.name}" deleted`);
1094
+ await refetch();
1095
+ } catch (err) {
1096
+ toast.error(`Failed to delete column: ${err instanceof Error ? err.message : "Unknown error"}`);
1097
+ }
1098
+ }, [selectedType, editingColumn, client, refetch]);
1099
+ const handleCreateTable = React4.useCallback(
1100
+ async (table) => {
1101
+ try {
1102
+ const columnDefs = table.columns.map((col) => {
1103
+ const nullable = col.isNullable ? "" : "NOT NULL";
1104
+ const pk = col.isPrimaryKey ? "PRIMARY KEY" : "";
1105
+ const defaultVal = col.defaultValue ? `DEFAULT '${col.defaultValue}'` : "";
1106
+ return `${col.name} ${col.dataType} ${pk} ${nullable} ${defaultVal}`.trim();
1107
+ }).join(", ");
1108
+ const sql = `CREATE TABLE ${table.name} (${columnDefs})`;
1109
+ await client.SQL.execute({ query: sql });
1110
+ setTableCreatorOpen(false);
1111
+ toast.success(`Table "${table.name}" created`);
1112
+ await refetch();
1113
+ } catch (err) {
1114
+ toast.error(`Failed to create table: ${err instanceof Error ? err.message : "Unknown error"}`);
1115
+ }
1116
+ },
1117
+ [client, refetch]
1118
+ );
1119
+ const handleCellUpdate = React4.useCallback(
1120
+ async (rowIndex, columnId, value) => {
1121
+ if (readOnly || !selectedType) return;
1122
+ const row = localData[rowIndex];
1123
+ const oldValue = row?.[columnId];
1124
+ const rowId = row?.id;
1125
+ pushOperation({ rowIndex, columnId, oldValue, newValue: value, type: "cell_update" });
1126
+ try {
1127
+ await client.Thing.update({
1128
+ ns: selectedNamespace,
1129
+ type: selectedType,
1130
+ id: rowId,
1131
+ data: { [columnId]: value }
1132
+ });
1133
+ toast.success("Cell updated");
1134
+ } catch (err) {
1135
+ undo();
1136
+ toast.error(`Failed to save cell: ${err instanceof Error ? err.message : "Unknown error"}`);
1137
+ }
1138
+ },
1139
+ [readOnly, selectedType, selectedNamespace, localData, pushOperation, undo, client]
1140
+ );
1141
+ const handleInsert = React4.useCallback(
1142
+ async (newRow) => {
1143
+ if (readOnly || !selectedType) return;
1144
+ try {
1145
+ await client.Thing.create({
1146
+ ns: selectedNamespace,
1147
+ type: selectedType,
1148
+ data: newRow
1149
+ });
1150
+ await refetch();
1151
+ toast.success("Row added successfully");
1152
+ } catch (err) {
1153
+ toast.error(`Failed to create row: ${err instanceof Error ? err.message : "Unknown error"}`);
1154
+ }
1155
+ },
1156
+ [readOnly, selectedType, selectedNamespace, client, refetch]
1157
+ );
1158
+ const handleDeleteRows = React4.useCallback(
1159
+ async (rowIds) => {
1160
+ if (readOnly || !selectedType) return;
1161
+ try {
1162
+ await Promise.all(
1163
+ rowIds.map(
1164
+ (id) => (
1165
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1166
+ client.Thing.delete({
1167
+ ns: selectedNamespace,
1168
+ type: selectedType,
1169
+ id
1170
+ })
1171
+ )
1172
+ )
1173
+ );
1174
+ setLocalData((prev) => prev.filter((row) => !rowIds.includes(String(row.id))));
1175
+ setSelectedRows([]);
1176
+ toast.success(`${rowIds.length} row${rowIds.length > 1 ? "s" : ""} deleted`);
1177
+ } catch (err) {
1178
+ toast.error(`Failed to delete rows: ${err instanceof Error ? err.message : "Unknown error"}`);
1179
+ }
1180
+ },
1181
+ [readOnly, selectedType, selectedNamespace, client]
1182
+ );
1183
+ const handleRefresh = React4.useCallback(async () => {
1184
+ setRefreshStatus("refreshing");
1185
+ try {
1186
+ await refetch();
1187
+ setRefreshStatus("success");
1188
+ setLastRefreshTime(/* @__PURE__ */ new Date());
1189
+ setTimeout(() => setRefreshStatus("idle"), 2e3);
1190
+ } catch {
1191
+ setRefreshStatus("error");
1192
+ setTimeout(() => setRefreshStatus("idle"), 3e3);
1193
+ }
1194
+ }, [refetch]);
1195
+ const handleToggleColumnVisibility = React4.useCallback((accessorKey) => {
1196
+ setHiddenColumns((prev) => {
1197
+ const next = new Set(prev);
1198
+ if (next.has(accessorKey)) {
1199
+ next.delete(accessorKey);
1200
+ } else {
1201
+ next.add(accessorKey);
1202
+ }
1203
+ return next;
1204
+ });
1205
+ }, []);
1206
+ const handleExport = React4.useCallback(
1207
+ (scope, format) => {
1208
+ const dataToExport = scope === "all" ? localData : scope === "filtered" ? filteredData : filteredData;
1209
+ let content;
1210
+ let mimeType;
1211
+ let extension;
1212
+ switch (format) {
1213
+ case "json":
1214
+ content = JSON.stringify(dataToExport, null, 2);
1215
+ mimeType = "application/json";
1216
+ extension = "json";
1217
+ break;
1218
+ case "csv": {
1219
+ const headers = visibleColumns.map((c) => c.header).join(",");
1220
+ const rows = dataToExport.map(
1221
+ (row) => visibleColumns.map((c) => JSON.stringify(row[c.accessorKey] ?? "")).join(",")
1222
+ );
1223
+ content = [headers, ...rows].join("\n");
1224
+ mimeType = "text/csv";
1225
+ extension = "csv";
1226
+ break;
1227
+ }
1228
+ default:
1229
+ content = JSON.stringify(dataToExport, null, 2);
1230
+ mimeType = "application/json";
1231
+ extension = "json";
1232
+ }
1233
+ const blob = new Blob([content], { type: mimeType });
1234
+ const url = URL.createObjectURL(blob);
1235
+ const link = document.createElement("a");
1236
+ link.href = url;
1237
+ link.download = `${selectedType ?? "data"}-${scope}.${extension}`;
1238
+ document.body.appendChild(link);
1239
+ link.click();
1240
+ document.body.removeChild(link);
1241
+ URL.revokeObjectURL(url);
1242
+ },
1243
+ [localData, filteredData, visibleColumns, selectedType]
1244
+ );
1245
+ const handleQueryExecute = React4.useCallback(
1246
+ async (query) => {
1247
+ const startTime = Date.now();
1248
+ try {
1249
+ const result = await client.SQL.execute({ query });
1250
+ return {
1251
+ rows: result.rows,
1252
+ columns: result.columns.map((col) => ({
1253
+ name: col.name,
1254
+ type: col.type
1255
+ })),
1256
+ rowsAffected: result.rowsAffected,
1257
+ executionTime: result.executionTimeMs ?? Date.now() - startTime
1258
+ };
1259
+ } catch (err) {
1260
+ throw new Error(err instanceof Error ? err.message : "Query execution failed");
1261
+ }
1262
+ },
1263
+ [client]
1264
+ );
1265
+ React4.useEffect(() => {
1266
+ const mediaQuery = window.matchMedia("(max-width: 768px)");
1267
+ const handleMediaChange = (e) => {
1268
+ if (e.matches) {
1269
+ setSidebarCollapsed(true);
1270
+ }
1271
+ };
1272
+ handleMediaChange(mediaQuery);
1273
+ mediaQuery.addEventListener("change", handleMediaChange);
1274
+ return () => mediaQuery.removeEventListener("change", handleMediaChange);
1275
+ }, []);
1276
+ React4.useEffect(() => {
1277
+ const handleKeyDown = (e) => {
1278
+ if ((e.metaKey || e.ctrlKey) && e.key === "z") {
1279
+ if (e.shiftKey) {
1280
+ e.preventDefault();
1281
+ redo();
1282
+ } else {
1283
+ e.preventDefault();
1284
+ undo();
1285
+ }
1286
+ }
1287
+ };
1288
+ document.addEventListener("keydown", handleKeyDown);
1289
+ return () => document.removeEventListener("keydown", handleKeyDown);
1290
+ }, [undo, redo]);
1291
+ React4.useEffect(() => {
1292
+ if (!autoRefreshEnabled) return;
1293
+ const intervalMs = autoRefreshInterval * 1e3;
1294
+ const timer = setInterval(handleRefresh, intervalMs);
1295
+ return () => clearInterval(timer);
1296
+ }, [autoRefreshEnabled, autoRefreshInterval, handleRefresh]);
1297
+ const [schema, tableName] = selectedTable.split(".");
1298
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
1299
+ /* @__PURE__ */ jsxs("div", { className: cn("flex h-full overflow-x-auto bg-background", className), children: [
1300
+ /* @__PURE__ */ jsx(
1301
+ DatabaseSidebar,
1302
+ {
1303
+ schemas,
1304
+ selectedTable,
1305
+ onSelectTable: handleSelectTable,
1306
+ onViewTable: (schema2, table) => handleSelectTable(schema2, table),
1307
+ onDuplicateTable: async (_schema, table) => {
1308
+ try {
1309
+ const sql = `CREATE TABLE ${table}_copy AS SELECT * FROM ${table}`;
1310
+ await client.SQL.execute({ query: sql });
1311
+ toast.success(`Table "${table}" duplicated as "${table}_copy"`);
1312
+ await refetch();
1313
+ } catch (err) {
1314
+ toast.error(`Failed to duplicate table: ${err instanceof Error ? err.message : "Unknown error"}`);
1315
+ }
1316
+ },
1317
+ onDeleteTable: async (_schema, table) => {
1318
+ try {
1319
+ await client.SQL.execute({ query: `DROP TABLE ${table}` });
1320
+ toast.success(`Table "${table}" deleted`);
1321
+ await refetch();
1322
+ } catch (err) {
1323
+ toast.error(`Failed to delete table: ${err instanceof Error ? err.message : "Unknown error"}`);
1324
+ }
1325
+ },
1326
+ onCreateTable: () => setTableCreatorOpen(true),
1327
+ collapsed: sidebarCollapsed,
1328
+ onCollapsedChange: setSidebarCollapsed,
1329
+ className: "shrink-0"
1330
+ }
1331
+ ),
1332
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-1 flex-col overflow-hidden min-w-[320px]", children: [
1333
+ /* @__PURE__ */ jsx(
1334
+ TableEditorToolbar,
1335
+ {
1336
+ schema,
1337
+ tableName: tableName || "Select a type",
1338
+ columns,
1339
+ totalRowCount: localData.length,
1340
+ filteredRowCount: filteredData.length,
1341
+ visibleRowCount: filteredData.length,
1342
+ selectedRowIds: selectedRows,
1343
+ onClearSelection: () => setSelectedRows([]),
1344
+ onDeleteSelectedRows: handleDeleteRows,
1345
+ sidebarCollapsed,
1346
+ onSidebarCollapsedChange: setSidebarCollapsed,
1347
+ viewMode,
1348
+ onViewModeChange: setViewMode,
1349
+ canUndo,
1350
+ canRedo,
1351
+ undoCount,
1352
+ redoCount,
1353
+ onUndo: undo,
1354
+ onRedo: redo,
1355
+ refreshStatus,
1356
+ onRefresh: handleRefresh,
1357
+ autoRefreshEnabled,
1358
+ onAutoRefreshEnabledChange: setAutoRefreshEnabled,
1359
+ autoRefreshInterval,
1360
+ onAutoRefreshIntervalChange: setAutoRefreshInterval,
1361
+ lastRefreshTime,
1362
+ filters,
1363
+ onFiltersChange: setFilters,
1364
+ hiddenColumns,
1365
+ onToggleColumnVisibility: handleToggleColumnVisibility,
1366
+ onInsertRow: () => gridActionsRef.current?.startNewRow(),
1367
+ onAddColumn: handleAddColumn,
1368
+ onExport: handleExport
1369
+ }
1370
+ ),
1371
+ viewMode === "table" ? /* @__PURE__ */ jsx("div", { className: "flex min-h-0 flex-1 flex-col p-2", children: isLoading ? /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center h-full", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-2", children: [
1372
+ /* @__PURE__ */ jsx("div", { className: "h-8 w-8 animate-spin rounded-full border-4 border-primary border-t-transparent" }),
1373
+ /* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: "Loading..." })
1374
+ ] }) }) : !selectedType ? /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center h-full text-muted-foreground", children: "Select a type from the sidebar to view data" }) : /* @__PURE__ */ jsx(
1375
+ DatabaseGrid,
1376
+ {
1377
+ data: filteredData,
1378
+ columns: visibleColumns,
1379
+ onCellUpdate: handleCellUpdate,
1380
+ onInsert: handleInsert,
1381
+ onDeleteRows: handleDeleteRows,
1382
+ onViewRow: (rowId) => {
1383
+ toast.info(`Row ID: ${rowId}`);
1384
+ },
1385
+ onDuplicateRow: async (_rowId, row) => {
1386
+ if (!selectedType) return;
1387
+ const { id, _ns, _type, ...data } = row;
1388
+ try {
1389
+ await client.Thing.create({
1390
+ ns: selectedNamespace,
1391
+ type: selectedType,
1392
+ data
1393
+ });
1394
+ await refetch();
1395
+ toast.success("Row duplicated");
1396
+ } catch (err) {
1397
+ toast.error(`Failed to duplicate row: ${err instanceof Error ? err.message : "Unknown error"}`);
1398
+ }
1399
+ },
1400
+ onSelectionChange: setSelectedRows,
1401
+ onColumnReorder: (order) => {
1402
+ if (selectedType) {
1403
+ localStorage.setItem(
1404
+ `do-column-order-${selectedNamespace}-${selectedType}`,
1405
+ JSON.stringify(order)
1406
+ );
1407
+ }
1408
+ },
1409
+ actionsRef: gridActionsRef,
1410
+ emptyMessage: "No data matches the current filters",
1411
+ className: "h-full"
1412
+ }
1413
+ ) }) : viewMode === "query" ? /* @__PURE__ */ jsx(
1414
+ QueryView,
1415
+ {
1416
+ currentTable: tableName || "",
1417
+ schema,
1418
+ onExecute: handleQueryExecute,
1419
+ className: "flex-1"
1420
+ }
1421
+ ) : /* @__PURE__ */ jsx(
1422
+ FormatView,
1423
+ {
1424
+ data: filteredData,
1425
+ columns,
1426
+ format: formatViewFormat,
1427
+ className: "flex-1"
1428
+ }
1429
+ )
1430
+ ] })
1431
+ ] }),
1432
+ /* @__PURE__ */ jsx(
1433
+ ColumnEditorPanel,
1434
+ {
1435
+ open: columnEditorOpen,
1436
+ onOpenChange: setColumnEditorOpen,
1437
+ column: editingColumn,
1438
+ referenceTables: types?.map((t) => ({
1439
+ name: t.name,
1440
+ columns: ["id", "name", "createdAt", "updatedAt"]
1441
+ })) ?? [],
1442
+ onSave: handleSaveColumn,
1443
+ onDelete: editingColumn ? handleDeleteColumn : void 0
1444
+ }
1445
+ ),
1446
+ /* @__PURE__ */ jsx(
1447
+ TableCreatorPanel,
1448
+ {
1449
+ open: tableCreatorOpen,
1450
+ onOpenChange: setTableCreatorOpen,
1451
+ schemas: namespaces?.map((ns) => ns.name) ?? ["default"],
1452
+ onCreate: handleCreateTable
1453
+ }
1454
+ ),
1455
+ /* @__PURE__ */ jsx(Toaster, { closeButton: true, position: "top-right" })
1456
+ ] });
1457
+ }
1458
+ DataGridView.displayName = "DataGridView";
1459
+ function toDocumentType(type) {
1460
+ return {
1461
+ id: type.id,
1462
+ name: type.name,
1463
+ label: type.label
1464
+ };
1465
+ }
1466
+ function toDocumentTypeOption(type) {
1467
+ return {
1468
+ id: type.id,
1469
+ name: type.name,
1470
+ label: type.label
1471
+ };
1472
+ }
1473
+ function toDocumentItem(thing) {
1474
+ return {
1475
+ id: thing.id,
1476
+ name: thing.name,
1477
+ type: thing.type
1478
+ };
1479
+ }
1480
+ function DocumentEditorView({
1481
+ initialNamespace,
1482
+ initialType,
1483
+ initialId,
1484
+ onSave,
1485
+ onDelete,
1486
+ onBack: _onBack,
1487
+ className
1488
+ }) {
1489
+ const { namespace: contextNamespace } = useDO();
1490
+ const [selectedNamespace] = React4.useState(initialNamespace ?? contextNamespace);
1491
+ const [selectedType, setSelectedType] = React4.useState(initialType);
1492
+ const [selectedThingId, setSelectedThingId] = React4.useState(initialId);
1493
+ const [sidebarCollapsed, setSidebarCollapsed] = React4.useState(false);
1494
+ const [hasUnsavedChanges, setHasUnsavedChanges] = React4.useState(false);
1495
+ const [isSaving, setIsSaving] = React4.useState(false);
1496
+ const [localDocument, setLocalDocument] = React4.useState(null);
1497
+ const fileInputRef = React4.useRef(null);
1498
+ const { data: types } = useTypes({ ns: selectedNamespace });
1499
+ const { data: thingsResult, refetch: refetchThings } = useThings({
1500
+ ns: selectedNamespace,
1501
+ type: selectedType
1502
+ });
1503
+ const thingParams = selectedType && selectedThingId ? { ns: selectedNamespace, type: selectedType, id: selectedThingId } : { ns: "", type: "", id: "" };
1504
+ const { data: currentThing, isLoading: isLoadingThing } = useThing(thingParams);
1505
+ const updateThing = useUpdateThing(
1506
+ selectedType && selectedThingId ? { ns: selectedNamespace, type: selectedType, id: selectedThingId } : { ns: "temp", type: "temp", id: "temp" }
1507
+ );
1508
+ const deleteThing = useDeleteThing(
1509
+ selectedType && selectedThingId ? { ns: selectedNamespace, type: selectedType, id: selectedThingId } : { ns: "temp", type: "temp", id: "temp" }
1510
+ );
1511
+ const documentTypes = React4.useMemo(
1512
+ () => types?.map(toDocumentType) ?? [],
1513
+ [types]
1514
+ );
1515
+ const documentTypeOptions = React4.useMemo(
1516
+ () => types?.map(toDocumentTypeOption) ?? [],
1517
+ [types]
1518
+ );
1519
+ const documentItems = React4.useMemo(
1520
+ () => thingsResult?.data?.map(toDocumentItem) ?? [],
1521
+ [thingsResult]
1522
+ );
1523
+ React4.useEffect(() => {
1524
+ if (currentThing) {
1525
+ setLocalDocument({
1526
+ _id: currentThing.id,
1527
+ _ns: currentThing.ns,
1528
+ _type: currentThing.type,
1529
+ name: currentThing.name,
1530
+ createdAt: currentThing.createdAt instanceof Date ? currentThing.createdAt.toISOString() : currentThing.createdAt,
1531
+ updatedAt: currentThing.updatedAt instanceof Date ? currentThing.updatedAt.toISOString() : currentThing.updatedAt,
1532
+ ...currentThing.data
1533
+ });
1534
+ setHasUnsavedChanges(false);
1535
+ } else {
1536
+ setLocalDocument(null);
1537
+ }
1538
+ }, [currentThing]);
1539
+ const handleSelectDocument = React4.useCallback((type, documentId) => {
1540
+ setSelectedType(type);
1541
+ setSelectedThingId(documentId);
1542
+ setHasUnsavedChanges(false);
1543
+ }, []);
1544
+ const handleDocumentChange = React4.useCallback((updatedDoc) => {
1545
+ setLocalDocument(updatedDoc);
1546
+ setHasUnsavedChanges(true);
1547
+ }, []);
1548
+ const handleCreateDocument = React4.useCallback((type) => {
1549
+ const newId = `${Date.now()}`;
1550
+ setSelectedType(type);
1551
+ setSelectedThingId(newId);
1552
+ setLocalDocument({
1553
+ _id: newId,
1554
+ _type: type,
1555
+ _ns: selectedNamespace,
1556
+ name: "New Thing",
1557
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
1558
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
1559
+ });
1560
+ setHasUnsavedChanges(true);
1561
+ }, [selectedNamespace]);
1562
+ const handleSave = React4.useCallback(async () => {
1563
+ if (!localDocument || !selectedType || !selectedThingId) return;
1564
+ setIsSaving(true);
1565
+ try {
1566
+ const { _id, _ns, _type, createdAt, updatedAt, name, ...data } = localDocument;
1567
+ await updateThing.mutateAsync({
1568
+ name,
1569
+ data
1570
+ });
1571
+ setHasUnsavedChanges(false);
1572
+ await refetchThings();
1573
+ if (onSave && currentThing) {
1574
+ onSave({ ...currentThing, name, data });
1575
+ }
1576
+ } catch (err) {
1577
+ console.error("Failed to save:", err);
1578
+ } finally {
1579
+ setIsSaving(false);
1580
+ }
1581
+ }, [localDocument, selectedType, selectedThingId, updateThing, refetchThings, onSave, currentThing]);
1582
+ const handleDelete = React4.useCallback(async () => {
1583
+ if (!selectedType || !selectedThingId) return;
1584
+ try {
1585
+ await deleteThing.mutateAsync();
1586
+ const remainingThings = thingsResult?.data?.filter((t) => t.id !== selectedThingId) ?? [];
1587
+ if (remainingThings.length > 0) {
1588
+ setSelectedThingId(remainingThings[0].id);
1589
+ setSelectedType(remainingThings[0].type);
1590
+ } else {
1591
+ setSelectedThingId(void 0);
1592
+ }
1593
+ setHasUnsavedChanges(false);
1594
+ await refetchThings();
1595
+ onDelete?.();
1596
+ } catch (err) {
1597
+ console.error("Failed to delete:", err);
1598
+ }
1599
+ }, [selectedType, selectedThingId, deleteThing, thingsResult, refetchThings, onDelete]);
1600
+ const handleExport = React4.useCallback(() => {
1601
+ if (!localDocument) return;
1602
+ const json = JSON.stringify(localDocument, null, 2);
1603
+ const blob = new Blob([json], { type: "application/json" });
1604
+ const url = URL.createObjectURL(blob);
1605
+ const link = document.createElement("a");
1606
+ link.href = url;
1607
+ link.download = `${selectedThingId}.json`;
1608
+ document.body.appendChild(link);
1609
+ link.click();
1610
+ document.body.removeChild(link);
1611
+ URL.revokeObjectURL(url);
1612
+ }, [localDocument, selectedThingId]);
1613
+ const handleImport = React4.useCallback(() => {
1614
+ fileInputRef.current?.click();
1615
+ }, []);
1616
+ const handleFileChange = React4.useCallback(
1617
+ (event) => {
1618
+ const file = event.target.files?.[0];
1619
+ if (!file || !selectedType) return;
1620
+ const reader = new FileReader();
1621
+ reader.onload = (e) => {
1622
+ try {
1623
+ const content = e.target?.result;
1624
+ const parsed = JSON.parse(content);
1625
+ if (typeof parsed !== "object" || parsed === null) {
1626
+ throw new Error("Invalid JSON: root must be an object");
1627
+ }
1628
+ const newId = `${Date.now()}`;
1629
+ setSelectedThingId(newId);
1630
+ setLocalDocument({
1631
+ ...parsed,
1632
+ _id: newId,
1633
+ _type: selectedType,
1634
+ _ns: selectedNamespace
1635
+ });
1636
+ setHasUnsavedChanges(true);
1637
+ } catch (err) {
1638
+ console.error("Failed to import document:", err);
1639
+ }
1640
+ };
1641
+ reader.readAsText(file);
1642
+ event.target.value = "";
1643
+ },
1644
+ [selectedType, selectedNamespace]
1645
+ );
1646
+ const handleRefresh = React4.useCallback(async () => {
1647
+ await refetchThings();
1648
+ setHasUnsavedChanges(false);
1649
+ }, [refetchThings]);
1650
+ React4.useEffect(() => {
1651
+ const mediaQuery = window.matchMedia("(max-width: 768px)");
1652
+ const handleMediaChange = (e) => {
1653
+ if (e.matches) {
1654
+ setSidebarCollapsed(true);
1655
+ }
1656
+ };
1657
+ handleMediaChange(mediaQuery);
1658
+ mediaQuery.addEventListener("change", handleMediaChange);
1659
+ return () => mediaQuery.removeEventListener("change", handleMediaChange);
1660
+ }, []);
1661
+ return /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsxs("div", { className: cn("flex h-full overflow-x-auto bg-background", className), children: [
1662
+ /* @__PURE__ */ jsx(
1663
+ "input",
1664
+ {
1665
+ ref: fileInputRef,
1666
+ type: "file",
1667
+ accept: ".json,application/json",
1668
+ className: "hidden",
1669
+ onChange: handleFileChange
1670
+ }
1671
+ ),
1672
+ /* @__PURE__ */ jsx(
1673
+ DocumentSidebar,
1674
+ {
1675
+ types: documentTypes,
1676
+ documents: documentItems,
1677
+ selectedType,
1678
+ selectedDocumentId: selectedThingId,
1679
+ onSelectDocument: handleSelectDocument,
1680
+ onCreateDocument: handleCreateDocument,
1681
+ collapsed: sidebarCollapsed
1682
+ }
1683
+ ),
1684
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-1 flex-col overflow-hidden min-w-[320px]", children: [
1685
+ /* @__PURE__ */ jsx(
1686
+ DocumentViewToolbar,
1687
+ {
1688
+ typeName: selectedType,
1689
+ documentName: localDocument ? localDocument.name : void 0,
1690
+ documentId: selectedThingId,
1691
+ hasUnsavedChanges,
1692
+ isSaving,
1693
+ hasDocument: !!localDocument,
1694
+ types: documentTypeOptions,
1695
+ sidebarCollapsed,
1696
+ onSidebarToggle: () => setSidebarCollapsed(!sidebarCollapsed),
1697
+ onSave: handleSave,
1698
+ onRefresh: handleRefresh,
1699
+ onImport: handleImport,
1700
+ onExport: handleExport,
1701
+ onDelete: handleDelete,
1702
+ onCreateNew: handleCreateDocument
1703
+ }
1704
+ ),
1705
+ /* @__PURE__ */ jsx("div", { className: "flex min-h-0 flex-1 flex-col", children: isLoadingThing ? /* @__PURE__ */ jsx("div", { className: "flex h-full items-center justify-center", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-2", children: [
1706
+ /* @__PURE__ */ jsx("div", { className: "h-8 w-8 animate-spin rounded-full border-4 border-primary border-t-transparent" }),
1707
+ /* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: "Loading..." })
1708
+ ] }) }) : localDocument ? /* @__PURE__ */ jsx(
1709
+ DocumentEditor,
1710
+ {
1711
+ document: localDocument,
1712
+ onChange: handleDocumentChange,
1713
+ className: "h-full"
1714
+ }
1715
+ ) : /* @__PURE__ */ jsxs("div", { className: "flex h-full flex-col items-center justify-center text-muted-foreground", children: [
1716
+ /* @__PURE__ */ jsx(Database, { className: "mb-4 h-12 w-12 opacity-20" }),
1717
+ /* @__PURE__ */ jsx("p", { className: "text-sm", children: "No document selected" }),
1718
+ /* @__PURE__ */ jsx("p", { className: "mt-1 text-xs", children: "Select a document from the sidebar or create a new one" })
1719
+ ] }) }),
1720
+ /* @__PURE__ */ jsxs("footer", { className: "flex h-10 shrink-0 items-center justify-between border-t bg-muted/30 px-2 sm:px-4 gap-4", children: [
1721
+ /* @__PURE__ */ jsx("div", { className: "text-xs text-muted-foreground whitespace-nowrap shrink-0", children: selectedType && /* @__PURE__ */ jsxs(Fragment, { children: [
1722
+ /* @__PURE__ */ jsx("span", { className: "font-medium text-foreground", children: thingsResult?.data?.filter((t) => t.type === selectedType).length ?? 0 }),
1723
+ " ",
1724
+ "documents in ",
1725
+ selectedType
1726
+ ] }) }),
1727
+ /* @__PURE__ */ jsx("div", { className: "text-xs text-muted-foreground truncate", children: localDocument && /* @__PURE__ */ jsxs(Fragment, { children: [
1728
+ "ID:",
1729
+ " ",
1730
+ /* @__PURE__ */ jsx("span", { className: "font-mono text-foreground", children: selectedThingId })
1731
+ ] }) })
1732
+ ] })
1733
+ ] })
1734
+ ] }) });
1735
+ }
1736
+ DocumentEditorView.displayName = "DocumentEditorView";
1737
+ var STARTER_TEMPLATES = [
1738
+ {
1739
+ id: "list-things",
1740
+ name: "List all Things",
1741
+ description: "List all Things in the namespace",
1742
+ code: `// List all Things
1743
+ const things = await client.things.list({
1744
+ limit: 100,
1745
+ })
1746
+
1747
+ return { things, relationships: [] }`
1748
+ },
1749
+ {
1750
+ id: "list-by-type",
1751
+ name: "List Things by type",
1752
+ description: "Filter Things by their semantic type",
1753
+ code: `// List Things by type
1754
+ const type = 'User' // Change this to your type
1755
+
1756
+ const things = await client.things.list({
1757
+ type,
1758
+ limit: 100,
1759
+ })
1760
+
1761
+ return { things, relationships: [] }`
1762
+ },
1763
+ {
1764
+ id: "get-thing",
1765
+ name: "Get single Thing",
1766
+ description: "Fetch a specific Thing by ID",
1767
+ code: `// Get a single Thing by ID
1768
+ const id = 'thing-id' // Replace with actual ID
1769
+
1770
+ const thing = await client.things.get(id)
1771
+
1772
+ return { things: [thing], relationships: [] }`
1773
+ },
1774
+ {
1775
+ id: "create-thing",
1776
+ name: "Create new Thing",
1777
+ description: "Create a new Thing in the namespace",
1778
+ code: `// Create a new Thing
1779
+ const newThing = await client.things.create({
1780
+ type: 'User',
1781
+ name: 'New User',
1782
+ data: {
1783
+ email: 'user@example.com',
1784
+ role: 'member',
1785
+ },
1786
+ })
1787
+
1788
+ return { things: [newThing], relationships: [] }`
1789
+ },
1790
+ {
1791
+ id: "update-thing",
1792
+ name: "Update a Thing",
1793
+ description: "Update an existing Thing",
1794
+ code: `// Update a Thing
1795
+ const id = 'thing-id' // Replace with actual ID
1796
+
1797
+ const updatedThing = await client.things.update(id, {
1798
+ name: 'Updated Name',
1799
+ data: {
1800
+ email: 'updated@example.com',
1801
+ },
1802
+ })
1803
+
1804
+ return { things: [updatedThing], relationships: [] }`
1805
+ },
1806
+ {
1807
+ id: "query-things",
1808
+ name: "Query with filters",
1809
+ description: "Complex query with multiple filters",
1810
+ code: `// Query Things with filters
1811
+ const things = await client.things.list({
1812
+ type: 'User',
1813
+ filter: {
1814
+ 'data.role': 'admin',
1815
+ },
1816
+ sort: '-createdAt',
1817
+ limit: 50,
1818
+ })
1819
+
1820
+ return { things, relationships: [] }`
1821
+ }
1822
+ ];
1823
+ function FunctionEditorView({
1824
+ initialCode,
1825
+ onCodeChange,
1826
+ className
1827
+ }) {
1828
+ const { client, namespace } = useDO();
1829
+ const editorControlsRef = React4.useRef(null);
1830
+ const [, forceUpdate] = React4.useReducer((x) => x + 1, 0);
1831
+ const [sidebarCollapsed, setSidebarCollapsed] = React4.useState(false);
1832
+ const [currentCode, setCurrentCode] = React4.useState(initialCode ?? STARTER_TEMPLATES[0].code);
1833
+ const [history, setHistory] = React4.useState([]);
1834
+ const [savedQueries, setSavedQueries] = React4.useState([]);
1835
+ const [saveDialogOpen, setSaveDialogOpen] = React4.useState(false);
1836
+ const [queryName, setQueryName] = React4.useState("");
1837
+ React4.useEffect(() => {
1838
+ const interval = setInterval(() => {
1839
+ if (editorControlsRef.current) {
1840
+ forceUpdate();
1841
+ }
1842
+ }, 100);
1843
+ return () => clearInterval(interval);
1844
+ }, []);
1845
+ const handleExecute = React4.useCallback(
1846
+ async (code) => {
1847
+ const startTime = performance.now();
1848
+ try {
1849
+ const AsyncFunction = Object.getPrototypeOf(async function() {
1850
+ }).constructor;
1851
+ const fn = new AsyncFunction("client", "namespace", code);
1852
+ const result = await fn(client, namespace);
1853
+ const executionTime = Math.round(performance.now() - startTime);
1854
+ const historyItem = {
1855
+ id: `hist_${Date.now()}`,
1856
+ code,
1857
+ timestamp: /* @__PURE__ */ new Date(),
1858
+ executionTime,
1859
+ resultCount: (result?.things?.length ?? 0) + (result?.relationships?.length ?? 0)
1860
+ };
1861
+ setHistory((prev) => [historyItem, ...prev].slice(0, 20));
1862
+ onCodeChange?.(code);
1863
+ return {
1864
+ things: result?.things ?? [],
1865
+ relationships: result?.relationships ?? [],
1866
+ executionTime
1867
+ };
1868
+ } catch (err) {
1869
+ const executionTime = Math.round(performance.now() - startTime);
1870
+ const historyItem = {
1871
+ id: `hist_${Date.now()}`,
1872
+ code,
1873
+ timestamp: /* @__PURE__ */ new Date(),
1874
+ executionTime,
1875
+ resultCount: 0
1876
+ };
1877
+ setHistory((prev) => [historyItem, ...prev].slice(0, 20));
1878
+ throw err;
1879
+ }
1880
+ },
1881
+ [client, namespace, onCodeChange]
1882
+ );
1883
+ const handleSelectHistory = React4.useCallback((code) => {
1884
+ setCurrentCode(code);
1885
+ }, []);
1886
+ const handleClearHistory = React4.useCallback(() => {
1887
+ setHistory([]);
1888
+ }, []);
1889
+ const handleSelectSavedQuery = React4.useCallback((query) => {
1890
+ setCurrentCode(query.code);
1891
+ }, []);
1892
+ const handleDeleteSavedQuery = React4.useCallback((id) => {
1893
+ setSavedQueries((prev) => prev.filter((q) => q.id !== id));
1894
+ }, []);
1895
+ const handleSelectTemplate = React4.useCallback((template) => {
1896
+ setCurrentCode(template.code);
1897
+ }, []);
1898
+ const handleSaveQuery = React4.useCallback(() => {
1899
+ if (!queryName.trim()) return;
1900
+ const newQuery = {
1901
+ id: `saved_${Date.now()}`,
1902
+ name: queryName.trim(),
1903
+ code: currentCode,
1904
+ createdAt: /* @__PURE__ */ new Date(),
1905
+ updatedAt: /* @__PURE__ */ new Date()
1906
+ };
1907
+ setSavedQueries((prev) => [newQuery, ...prev]);
1908
+ setSaveDialogOpen(false);
1909
+ setQueryName("");
1910
+ }, [queryName, currentCode]);
1911
+ const toolbarHistory = editorControlsRef.current?.history?.map((item) => ({
1912
+ code: item.code,
1913
+ timestamp: item.timestamp
1914
+ })) ?? [];
1915
+ return /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsxs("div", { className: cn("flex h-full bg-background", className), children: [
1916
+ /* @__PURE__ */ jsx(
1917
+ FunctionSidebar,
1918
+ {
1919
+ title: "Function Editor",
1920
+ templates: STARTER_TEMPLATES,
1921
+ savedQueries,
1922
+ history,
1923
+ collapsed: sidebarCollapsed,
1924
+ onCollapsedChange: setSidebarCollapsed,
1925
+ onSelectTemplate: handleSelectTemplate,
1926
+ onSelectSavedQuery: handleSelectSavedQuery,
1927
+ onDeleteSavedQuery: handleDeleteSavedQuery,
1928
+ onSelectHistory: handleSelectHistory,
1929
+ onClearHistory: handleClearHistory
1930
+ }
1931
+ ),
1932
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-1 flex-col overflow-hidden min-w-[320px]", children: [
1933
+ /* @__PURE__ */ jsx(
1934
+ FunctionViewToolbar,
1935
+ {
1936
+ sidebarCollapsed,
1937
+ onSidebarToggle: () => setSidebarCollapsed(!sidebarCollapsed),
1938
+ isExecuting: editorControlsRef.current?.isExecuting,
1939
+ disabled: editorControlsRef.current?.disabled,
1940
+ onRun: () => editorControlsRef.current?.execute(),
1941
+ onClear: () => editorControlsRef.current?.clear(),
1942
+ history: toolbarHistory,
1943
+ onSelectHistory: (code) => editorControlsRef.current?.selectHistory(code),
1944
+ canSave: !!currentCode.trim(),
1945
+ onSave: () => setSaveDialogOpen(true)
1946
+ }
1947
+ ),
1948
+ /* @__PURE__ */ jsx("div", { className: "flex-1 h-0 overflow-hidden", children: /* @__PURE__ */ jsx(
1949
+ SDKEditor,
1950
+ {
1951
+ initialCode: currentCode,
1952
+ onExecute: handleExecute,
1953
+ defaultResultTab: "table",
1954
+ showToolbar: false,
1955
+ controlsRef: editorControlsRef,
1956
+ className: "h-full"
1957
+ }
1958
+ ) })
1959
+ ] }),
1960
+ /* @__PURE__ */ jsx(Dialog, { open: saveDialogOpen, onOpenChange: setSaveDialogOpen, children: /* @__PURE__ */ jsxs(DialogContent, { children: [
1961
+ /* @__PURE__ */ jsxs(DialogHeader, { children: [
1962
+ /* @__PURE__ */ jsx(DialogTitle, { children: "Save Query" }),
1963
+ /* @__PURE__ */ jsx(DialogDescription, { children: "Give your query a name to save it for later use." })
1964
+ ] }),
1965
+ /* @__PURE__ */ jsx("div", { className: "py-4", children: /* @__PURE__ */ jsx(
1966
+ Input,
1967
+ {
1968
+ placeholder: "Query name...",
1969
+ value: queryName,
1970
+ onChange: (e) => setQueryName(e.target.value),
1971
+ onKeyDown: (e) => {
1972
+ if (e.key === "Enter") {
1973
+ handleSaveQuery();
1974
+ }
1975
+ },
1976
+ autoFocus: true
1977
+ }
1978
+ ) }),
1979
+ /* @__PURE__ */ jsxs(DialogFooter, { children: [
1980
+ /* @__PURE__ */ jsx(Button, { variant: "outline", onClick: () => setSaveDialogOpen(false), children: "Cancel" }),
1981
+ /* @__PURE__ */ jsx(Button, { onClick: handleSaveQuery, disabled: !queryName.trim(), children: "Save" })
1982
+ ] })
1983
+ ] }) }),
1984
+ /* @__PURE__ */ jsx(Toaster, { closeButton: true, position: "top-right" })
1985
+ ] }) });
1986
+ }
1987
+ FunctionEditorView.displayName = "FunctionEditorView";
1988
+
1989
+ export { CreateDialog, DataBrowserView, DataGridView, DetailSheet, DocumentEditorView, FunctionEditorView, exportToJSON, formatDate, formatFieldName, isISODateString };
1990
+ //# sourceMappingURL=chunk-YGIBMNRH.js.map
1991
+ //# sourceMappingURL=chunk-YGIBMNRH.js.map