@object-ui/app-shell 6.1.0 → 6.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/CHANGELOG.md +110 -0
  2. package/README.md +10 -1
  3. package/dist/console/AppContent.js +24 -2
  4. package/dist/console/ai/AiChatPage.d.ts +8 -0
  5. package/dist/console/ai/AiChatPage.js +188 -0
  6. package/dist/console/ai/ConversationsSidebar.d.ts +7 -0
  7. package/dist/console/ai/ConversationsSidebar.js +111 -0
  8. package/dist/console/auth/LoginPage.js +19 -2
  9. package/dist/console/auth/RegisterPage.js +30 -1
  10. package/dist/console/marketplace/MarketplaceAccessDenied.js +3 -1
  11. package/dist/console/marketplace/MarketplaceInstalledPage.js +11 -3
  12. package/dist/console/marketplace/MarketplacePackagePage.js +57 -19
  13. package/dist/console/marketplace/MarketplacePage.js +55 -18
  14. package/dist/console/marketplace/marketplaceApi.d.ts +20 -0
  15. package/dist/console/marketplace/usePackageL10n.d.ts +38 -0
  16. package/dist/console/marketplace/usePackageL10n.js +110 -0
  17. package/dist/console/organizations/CreateWorkspaceDialog.js +29 -1
  18. package/dist/console/organizations/OrganizationsPage.js +24 -3
  19. package/dist/context/FavoritesProvider.d.ts +40 -2
  20. package/dist/context/FavoritesProvider.js +201 -20
  21. package/dist/hooks/index.d.ts +1 -0
  22. package/dist/hooks/index.js +1 -0
  23. package/dist/hooks/useChatConversation.d.ts +7 -0
  24. package/dist/hooks/useChatConversation.js +37 -5
  25. package/dist/hooks/useConversationList.d.ts +25 -0
  26. package/dist/hooks/useConversationList.js +131 -0
  27. package/dist/hooks/useNavPins.d.ts +11 -4
  28. package/dist/hooks/useNavPins.js +104 -53
  29. package/dist/index.d.ts +7 -0
  30. package/dist/index.js +14 -0
  31. package/dist/layout/AppHeader.js +2 -2
  32. package/dist/layout/AppSidebar.js +20 -1
  33. package/dist/layout/UnifiedSidebar.js +1 -1
  34. package/dist/providers/ExpressionProvider.d.ts +11 -1
  35. package/dist/providers/ExpressionProvider.js +11 -6
  36. package/dist/services/builtinComponents.d.ts +1 -0
  37. package/dist/services/builtinComponents.js +166 -0
  38. package/dist/services/componentRegistry.d.ts +63 -0
  39. package/dist/services/componentRegistry.js +36 -0
  40. package/dist/views/ComponentNavView.d.ts +6 -0
  41. package/dist/views/ComponentNavView.js +26 -0
  42. package/dist/views/RecordDetailView.js +66 -6
  43. package/dist/views/RecordFormPage.js +15 -3
  44. package/dist/views/SearchResultsPage.js +4 -0
  45. package/dist/views/metadata-admin/DesignerEditorWrapper.d.ts +58 -0
  46. package/dist/views/metadata-admin/DesignerEditorWrapper.js +140 -0
  47. package/dist/views/metadata-admin/DirectoryPage.d.ts +1 -0
  48. package/dist/views/metadata-admin/DirectoryPage.js +135 -0
  49. package/dist/views/metadata-admin/LayeredDiff.d.ts +6 -0
  50. package/dist/views/metadata-admin/LayeredDiff.js +26 -0
  51. package/dist/views/metadata-admin/PageShell.d.ts +34 -0
  52. package/dist/views/metadata-admin/PageShell.js +33 -0
  53. package/dist/views/metadata-admin/PermissionMatrixEditor.d.ts +5 -0
  54. package/dist/views/metadata-admin/PermissionMatrixEditor.js +288 -0
  55. package/dist/views/metadata-admin/QuickFind.d.ts +5 -0
  56. package/dist/views/metadata-admin/QuickFind.js +152 -0
  57. package/dist/views/metadata-admin/ResourceEditPage.d.ts +7 -0
  58. package/dist/views/metadata-admin/ResourceEditPage.js +256 -0
  59. package/dist/views/metadata-admin/ResourceHistoryPage.d.ts +5 -0
  60. package/dist/views/metadata-admin/ResourceHistoryPage.js +97 -0
  61. package/dist/views/metadata-admin/ResourceListPage.d.ts +4 -0
  62. package/dist/views/metadata-admin/ResourceListPage.js +144 -0
  63. package/dist/views/metadata-admin/ResourceRouter.d.ts +10 -0
  64. package/dist/views/metadata-admin/ResourceRouter.js +47 -0
  65. package/dist/views/metadata-admin/SchemaForm.d.ts +99 -0
  66. package/dist/views/metadata-admin/SchemaForm.js +556 -0
  67. package/dist/views/metadata-admin/default-schemas.d.ts +6 -0
  68. package/dist/views/metadata-admin/default-schemas.js +207 -0
  69. package/dist/views/metadata-admin/i18n.d.ts +33 -0
  70. package/dist/views/metadata-admin/i18n.js +303 -0
  71. package/dist/views/metadata-admin/index.d.ts +31 -0
  72. package/dist/views/metadata-admin/index.js +33 -0
  73. package/dist/views/metadata-admin/predicate.d.ts +31 -0
  74. package/dist/views/metadata-admin/predicate.js +150 -0
  75. package/dist/views/metadata-admin/registry.d.ts +125 -0
  76. package/dist/views/metadata-admin/registry.js +48 -0
  77. package/dist/views/metadata-admin/useMetadata.d.ts +37 -0
  78. package/dist/views/metadata-admin/useMetadata.js +96 -0
  79. package/dist/views/metadata-admin/widgets.d.ts +68 -0
  80. package/dist/views/metadata-admin/widgets.js +287 -0
  81. package/package.json +27 -26
@@ -0,0 +1,287 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ // Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
3
+ /**
4
+ * Built-in widget renderers for SchemaForm.
5
+ *
6
+ * These cover the common widget hints declared in spec `*.form.ts`
7
+ * files (e.g. `widget: 'ref:object'`, `widget: 'master-detail'`).
8
+ *
9
+ * Each widget receives `WidgetProps`:
10
+ * - schema — the JSONSchema fragment for THIS field (so widgets
11
+ * for nested arrays can read items.properties)
12
+ * - value — the current value
13
+ * - onChange — write-back callback
14
+ * - readOnly — disable
15
+ * - context — out-of-band data (object list, ObjectQL fields, …)
16
+ *
17
+ * To register a new widget, add an entry to `WIDGETS` below. To wire
18
+ * extra context (e.g. a fields list), extend `WidgetContext` in
19
+ * SchemaForm.tsx and prefetch it in ResourceEditPage.
20
+ */
21
+ import * as React from 'react';
22
+ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, Input, Button, } from '@object-ui/components';
23
+ import { Plus, Trash2 } from 'lucide-react';
24
+ /* -------------------------------------------------------------------------- */
25
+ /* ref:object — pick an object by name */
26
+ /* -------------------------------------------------------------------------- */
27
+ function RefObjectWidget({ id, value, onChange, readOnly, context, }) {
28
+ const names = context?.objectNames ?? [];
29
+ const v = value == null ? '' : String(value);
30
+ if (context?.objectsLoading) {
31
+ return (_jsx(Input, { id: id, value: v, disabled: true, placeholder: "Loading objects\u2026" }));
32
+ }
33
+ // If list is empty (e.g. no objects defined yet), fall back to a
34
+ // freeform text input so the user can still type a value.
35
+ if (names.length === 0) {
36
+ return (_jsx(Input, { id: id, value: v, disabled: readOnly, onChange: (e) => onChange(e.target.value || undefined), placeholder: "object_name (no objects detected)" }));
37
+ }
38
+ return (_jsxs(Select, { value: v, onValueChange: (next) => onChange(next || undefined), disabled: readOnly, children: [_jsx(SelectTrigger, { id: id, children: _jsx(SelectValue, { placeholder: "Select object\u2026" }) }), _jsx(SelectContent, { children: names.map((n) => (_jsx(SelectItem, { value: n, children: n }, n))) })] }));
39
+ }
40
+ /* -------------------------------------------------------------------------- */
41
+ /* object-selector — multi-select object picker */
42
+ /* -------------------------------------------------------------------------- */
43
+ function ObjectSelectorWidget({ id, value, onChange, readOnly, context, fieldSpec, }) {
44
+ const names = context?.objectNames ?? [];
45
+ const multiple = fieldSpec?.multiple ?? false;
46
+ // Parse value: string[], string (comma-separated), or empty
47
+ const selectedValues = React.useMemo(() => {
48
+ if (!value)
49
+ return [];
50
+ if (Array.isArray(value))
51
+ return value.map(String);
52
+ return String(value).split(',').map(s => s.trim()).filter(Boolean);
53
+ }, [value]);
54
+ const handleToggle = (objName) => {
55
+ if (readOnly)
56
+ return;
57
+ if (!multiple) {
58
+ onChange(objName);
59
+ return;
60
+ }
61
+ const newSelection = selectedValues.includes(objName)
62
+ ? selectedValues.filter(v => v !== objName)
63
+ : [...selectedValues, objName];
64
+ onChange(newSelection);
65
+ };
66
+ const handleRemove = (objName) => {
67
+ if (readOnly)
68
+ return;
69
+ const newSelection = selectedValues.filter(v => v !== objName);
70
+ onChange(multiple ? newSelection : '');
71
+ };
72
+ if (context?.objectsLoading) {
73
+ return _jsx(Input, { id: id, value: "Loading objects...", readOnly: true, disabled: true });
74
+ }
75
+ return (_jsxs("div", { className: "space-y-2", children: [selectedValues.length > 0 && (_jsx("div", { className: "flex flex-wrap gap-2", children: selectedValues.map(obj => (_jsxs("div", { className: "inline-flex items-center gap-1 rounded bg-secondary px-2 py-1 text-sm", children: [_jsx("span", { children: obj }), !readOnly && (_jsx("button", { type: "button", onClick: () => handleRemove(obj), className: "text-muted-foreground hover:text-foreground", children: "\u00D7" }))] }, obj))) })), _jsxs(Select, { value: "", onValueChange: handleToggle, disabled: readOnly || names.length === 0, children: [_jsx(SelectTrigger, { id: id, children: _jsx(SelectValue, { placeholder: multiple ? "Add objects..." : "Select object..." }) }), _jsx(SelectContent, { children: names.map(name => (_jsxs(SelectItem, { value: name, disabled: !multiple && selectedValues.includes(name), children: [name, selectedValues.includes(name) && ' ✓'] }, name))) })] })] }));
76
+ }
77
+ /* -------------------------------------------------------------------------- */
78
+ /* field-selector — smart field picker (depends on selected object) */
79
+ /* -------------------------------------------------------------------------- */
80
+ function FieldSelectorWidget({ id, value, onChange, readOnly, fieldSpec, formData, }) {
81
+ const [fields, setFields] = React.useState([]);
82
+ const [loading, setLoading] = React.useState(false);
83
+ // Resolve dependency: fieldSpec.dependsOn or fieldSpec.reference or 'objectName'
84
+ const dependsOnRaw = fieldSpec?.dependsOn || fieldSpec?.reference || 'objectName';
85
+ const dependsOnField = Array.isArray(dependsOnRaw) ? dependsOnRaw[0] : dependsOnRaw;
86
+ const objectName = formData?.[dependsOnField];
87
+ // Load fields when objectName changes
88
+ React.useEffect(() => {
89
+ if (!objectName) {
90
+ setFields([]);
91
+ return;
92
+ }
93
+ setLoading(true);
94
+ fetch(`/api/v1/objects/${objectName}/fields`)
95
+ .then(r => r.json())
96
+ .then(data => {
97
+ setFields(data.fields || []);
98
+ setLoading(false);
99
+ })
100
+ .catch(err => {
101
+ console.error('Failed to load fields:', err);
102
+ setFields([]);
103
+ setLoading(false);
104
+ });
105
+ }, [objectName]);
106
+ const multiple = fieldSpec?.multiple ?? false;
107
+ // Parse value
108
+ const selectedValues = React.useMemo(() => {
109
+ if (!value)
110
+ return [];
111
+ if (Array.isArray(value))
112
+ return value.map(String);
113
+ return String(value).split(',').map(s => s.trim()).filter(Boolean);
114
+ }, [value]);
115
+ const handleToggle = (fieldName) => {
116
+ if (readOnly)
117
+ return;
118
+ if (!multiple) {
119
+ onChange(fieldName);
120
+ return;
121
+ }
122
+ const newSelection = selectedValues.includes(fieldName)
123
+ ? selectedValues.filter(v => v !== fieldName)
124
+ : [...selectedValues, fieldName];
125
+ onChange(newSelection);
126
+ };
127
+ const handleRemove = (fieldName) => {
128
+ if (readOnly)
129
+ return;
130
+ const newSelection = selectedValues.filter(v => v !== fieldName);
131
+ onChange(multiple ? newSelection : '');
132
+ };
133
+ if (!objectName) {
134
+ return _jsx(Input, { id: id, value: "(Select an object first)", readOnly: true, disabled: true });
135
+ }
136
+ if (loading) {
137
+ return _jsx(Input, { id: id, value: "Loading fields...", readOnly: true, disabled: true });
138
+ }
139
+ return (_jsxs("div", { className: "space-y-2", children: [selectedValues.length > 0 && (_jsx("div", { className: "flex flex-wrap gap-2", children: selectedValues.map(field => {
140
+ const fieldMeta = fields.find(f => f.name === field);
141
+ return (_jsxs("div", { className: "inline-flex items-center gap-1 rounded bg-secondary px-2 py-1 text-sm", children: [_jsx("span", { children: fieldMeta?.label || field }), _jsx("code", { className: "text-xs text-muted-foreground", children: fieldMeta?.type }), !readOnly && (_jsx("button", { type: "button", onClick: () => handleRemove(field), className: "text-muted-foreground hover:text-foreground", children: "\u00D7" }))] }, field));
142
+ }) })), _jsxs(Select, { value: "", onValueChange: handleToggle, disabled: readOnly || fields.length === 0, children: [_jsx(SelectTrigger, { id: id, children: _jsx(SelectValue, { placeholder: multiple ? "Add fields..." : "Select field..." }) }), _jsx(SelectContent, { children: fields.map(f => (_jsx(SelectItem, { value: f.name, disabled: !multiple && selectedValues.includes(f.name), children: _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("span", { children: f.label || f.name }), _jsx("code", { className: "text-xs text-muted-foreground", children: f.type }), selectedValues.includes(f.name) && ' ✓'] }) }, f.name))) })] })] }));
143
+ }
144
+ /* -------------------------------------------------------------------------- */
145
+ /* master-detail — inline row editor for array-of-object fields */
146
+ /* -------------------------------------------------------------------------- */
147
+ function MasterDetailWidget({ schema, value, onChange, readOnly, context, }) {
148
+ // Unwrap anyOf/oneOf: pick the first array-of-object branch.
149
+ let resolved = schema;
150
+ if (resolved?.anyOf || resolved?.oneOf) {
151
+ const branches = (resolved.anyOf ?? resolved.oneOf);
152
+ const objBranch = branches.find((b) => b?.type === 'array' && b?.items?.type === 'object');
153
+ if (objBranch)
154
+ resolved = { ...resolved, ...objBranch };
155
+ }
156
+ const items = (resolved?.items ?? {});
157
+ const itemProps = (items.properties ?? {});
158
+ const required = new Set(Array.isArray(items.required) ? items.required : []);
159
+ const rows = Array.isArray(value) ? value : [];
160
+ const cols = Object.keys(itemProps);
161
+ if (cols.length === 0) {
162
+ // Falls back to JSON if the array items aren't a typed object.
163
+ return (_jsxs("div", { className: "rounded border border-dashed border-amber-500/40 bg-amber-500/5 p-2 text-xs text-amber-700 dark:text-amber-300", children: ["master-detail widget requires ", _jsx("code", { children: "items.properties" }), " on the JSON schema (or an ", _jsx("code", { children: "anyOf" }), " branch that has them)."] }));
164
+ }
165
+ function updateRow(idx, patch) {
166
+ const next = rows.slice();
167
+ next[idx] = { ...(next[idx] ?? {}), ...patch };
168
+ onChange(next);
169
+ }
170
+ function addRow() {
171
+ onChange([...rows, {}]);
172
+ }
173
+ function removeRow(idx) {
174
+ const next = rows.slice();
175
+ next.splice(idx, 1);
176
+ onChange(next);
177
+ }
178
+ return (_jsxs("div", { className: "space-y-2", children: [_jsx("div", { className: "overflow-x-auto rounded border border-border/40", children: _jsxs("table", { className: "w-full text-sm", children: [_jsx("thead", { className: "bg-muted/40", children: _jsxs("tr", { children: [cols.map((c) => (_jsxs("th", { className: "px-2 py-1.5 text-left text-xs font-medium text-muted-foreground", children: [itemProps[c]?.title ?? c, required.has(c) && (_jsx("span", { className: "text-destructive ml-0.5", children: "*" }))] }, c))), _jsx("th", { className: "w-8" })] }) }), _jsxs("tbody", { children: [rows.length === 0 && (_jsx("tr", { children: _jsx("td", { colSpan: cols.length + 1, className: "px-2 py-3 text-center text-xs text-muted-foreground", children: "No rows. Click + to add." }) })), rows.map((row, idx) => (_jsxs("tr", { className: "border-t border-border/30", children: [cols.map((c) => (_jsx("td", { className: "p-1", children: _jsx(RowCell, { schema: itemProps[c], value: (row ?? {})[c], readOnly: readOnly, context: context, onChange: (v) => updateRow(idx, { [c]: v }) }) }, c))), _jsx("td", { className: "p-1 text-right", children: _jsx(Button, { type: "button", variant: "ghost", size: "sm", onClick: () => removeRow(idx), disabled: readOnly, className: "h-7 w-7 p-0", "aria-label": "Remove row", children: _jsx(Trash2, { className: "h-3.5 w-3.5" }) }) })] }, idx)))] })] }) }), _jsxs(Button, { type: "button", variant: "outline", size: "sm", onClick: addRow, disabled: readOnly, children: [_jsx(Plus, { className: "h-3.5 w-3.5 mr-1" }), " Add row"] })] }));
179
+ }
180
+ function RowCell({ schema, value, readOnly, context, onChange, }) {
181
+ // ref:object hint inside a row cell
182
+ if (schema?.widget === 'ref:object') {
183
+ return (_jsx(RefObjectWidget, { schema: schema, value: value, onChange: onChange, readOnly: readOnly, context: context }));
184
+ }
185
+ // enum → dropdown
186
+ const enumVals = schema?.enum;
187
+ if (Array.isArray(enumVals) && enumVals.length > 0) {
188
+ return (_jsxs(Select, { value: value == null ? '' : String(value), onValueChange: (v) => onChange(v || undefined), disabled: readOnly, children: [_jsx(SelectTrigger, { className: "h-8 text-xs", children: _jsx(SelectValue, { placeholder: "\u2014" }) }), _jsx(SelectContent, { children: enumVals.map((o) => (_jsx(SelectItem, { value: String(o), children: String(o) }, String(o)))) })] }));
189
+ }
190
+ // boolean → checkbox-ish
191
+ if (schema?.type === 'boolean') {
192
+ return (_jsx("input", { type: "checkbox", checked: !!value, disabled: readOnly, onChange: (e) => onChange(e.target.checked), className: "h-4 w-4" }));
193
+ }
194
+ // number
195
+ if (schema?.type === 'number' || schema?.type === 'integer') {
196
+ return (_jsx(Input, { type: "number", value: value == null ? '' : String(value), disabled: readOnly, onChange: (e) => {
197
+ const n = e.target.valueAsNumber;
198
+ onChange(Number.isFinite(n) ? n : undefined);
199
+ }, className: "h-8 text-xs" }));
200
+ }
201
+ // default: text
202
+ return (_jsx(Input, { value: value == null ? '' : String(value), disabled: readOnly, onChange: (e) => onChange(e.target.value || undefined), className: "h-8 text-xs" }));
203
+ }
204
+ /* -------------------------------------------------------------------------- */
205
+ /* string-tags — chip input for string[] (e.g. searchableFields) */
206
+ /* -------------------------------------------------------------------------- */
207
+ function StringTagsWidget({ id, value, onChange, readOnly, }) {
208
+ const tags = Array.isArray(value) ? value : [];
209
+ const [draft, setDraft] = React.useState('');
210
+ function add(raw) {
211
+ const parts = raw
212
+ .split(/[,\n]/)
213
+ .map((s) => s.trim())
214
+ .filter(Boolean);
215
+ if (parts.length === 0)
216
+ return;
217
+ const next = [...tags];
218
+ for (const p of parts)
219
+ if (!next.includes(p))
220
+ next.push(p);
221
+ onChange(next);
222
+ setDraft('');
223
+ }
224
+ function remove(idx) {
225
+ const next = tags.slice();
226
+ next.splice(idx, 1);
227
+ onChange(next);
228
+ }
229
+ return (_jsx("div", { className: "rounded border border-input bg-background p-1.5", children: _jsxs("div", { className: "flex flex-wrap items-center gap-1", children: [tags.map((t, i) => (_jsxs("span", { className: "inline-flex items-center gap-1 rounded bg-muted px-1.5 py-0.5 text-xs", children: [_jsx("span", { className: "font-mono", children: t }), !readOnly && (_jsx("button", { type: "button", "aria-label": `Remove ${t}`, onClick: () => remove(i), className: "text-muted-foreground hover:text-destructive", children: "\u00D7" }))] }, i))), _jsx("input", { id: id, type: "text", value: draft, disabled: readOnly, placeholder: tags.length === 0 ? 'Type and press Enter…' : '', onChange: (e) => setDraft(e.target.value), onKeyDown: (e) => {
230
+ if (e.key === 'Enter' || e.key === ',') {
231
+ e.preventDefault();
232
+ add(draft);
233
+ }
234
+ else if (e.key === 'Backspace' && !draft && tags.length > 0) {
235
+ remove(tags.length - 1);
236
+ }
237
+ }, onBlur: () => draft && add(draft), className: "min-w-[8rem] flex-1 bg-transparent text-sm outline-none" })] }) }));
238
+ }
239
+ /* -------------------------------------------------------------------------- */
240
+ /* registry */
241
+ /* -------------------------------------------------------------------------- */
242
+ export const WIDGETS = {
243
+ 'ref:object': RefObjectWidget,
244
+ 'object-selector': ObjectSelectorWidget,
245
+ 'field-selector': FieldSelectorWidget,
246
+ 'master-detail': MasterDetailWidget,
247
+ 'string-tags': StringTagsWidget,
248
+ 'code': CodeWidget,
249
+ // Reasonable fallbacks until dedicated builders ship:
250
+ 'filter-builder': MasterDetailWidget,
251
+ };
252
+ /* -------------------------------------------------------------------------- */
253
+ /* CodeWidget — Monaco editor for `type: 'code'` fields */
254
+ /* -------------------------------------------------------------------------- */
255
+ /**
256
+ * Infer language from fieldSpec.language → schema.format → field name.
257
+ */
258
+ function inferCodeLanguage(fieldSpec, schema) {
259
+ if (fieldSpec?.language)
260
+ return fieldSpec.language;
261
+ if (typeof schema?.format === 'string') {
262
+ const f = schema.format.toLowerCase();
263
+ if (f === 'sql' || f === 'javascript' || f === 'typescript' || f === 'json' || f === 'yaml' || f === 'html' || f === 'css' || f === 'python')
264
+ return f;
265
+ }
266
+ // Common hook/action field name heuristics
267
+ const name = fieldSpec?.field?.toLowerCase() ?? '';
268
+ if (name.includes('sql') || name === 'query')
269
+ return 'sql';
270
+ if (name === 'source' || name === 'body' || name === 'script' || name === 'handler')
271
+ return 'javascript';
272
+ if (name === 'expression' || name === 'predicate' || name === 'formula' || name === 'condition')
273
+ return 'javascript';
274
+ return 'javascript';
275
+ }
276
+ const LazyCodeEditor = React.lazy(() => import('@object-ui/plugin-editor').then((m) => ({ default: m.CodeEditorRenderer })));
277
+ export function CodeWidget({ schema, value, onChange, readOnly, fieldSpec, }) {
278
+ const language = inferCodeLanguage(fieldSpec, schema);
279
+ const stringValue = typeof value === 'string' ? value : (value == null ? '' : String(value));
280
+ return (_jsxs("div", { className: "rounded-md border border-border/50 overflow-hidden", children: [_jsxs("div", { className: "flex items-center justify-between px-2 py-1 bg-muted/40 border-b border-border/30 text-[10px] font-mono text-muted-foreground", children: [_jsx("span", { children: language }), readOnly && _jsx("span", { children: "read-only" })] }), _jsx(React.Suspense, { fallback: _jsx("div", { className: "h-[280px] flex items-center justify-center text-xs text-muted-foreground", children: "Loading editor\u2026" }), children: _jsx(LazyCodeEditor, { schema: {
281
+ type: 'code',
282
+ language,
283
+ theme: 'vs-dark',
284
+ height: '280px',
285
+ readOnly,
286
+ }, value: stringValue, onChange: (v) => onChange(v ?? '') }) })] }));
287
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@object-ui/app-shell",
3
- "version": "6.1.0",
3
+ "version": "6.2.0",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "description": "Minimal application shell for ObjectUI - framework-agnostic rendering engine",
@@ -25,38 +25,39 @@
25
25
  "./styles.css": "./src/styles.css"
26
26
  },
27
27
  "dependencies": {
28
- "@sentry/react": "^8.55.2",
28
+ "@sentry/react": "^10.53.1",
29
29
  "lucide-react": "^1.16.0",
30
30
  "sonner": "^2.0.7",
31
- "@object-ui/auth": "6.1.0",
32
- "@object-ui/collaboration": "6.1.0",
33
- "@object-ui/components": "6.1.0",
34
- "@object-ui/core": "6.1.0",
35
- "@object-ui/data-objectstack": "6.1.0",
36
- "@object-ui/fields": "6.1.0",
37
- "@object-ui/i18n": "6.1.0",
38
- "@object-ui/layout": "6.1.0",
39
- "@object-ui/permissions": "6.1.0",
40
- "@object-ui/providers": "6.1.0",
41
- "@object-ui/react": "6.1.0",
42
- "@object-ui/types": "6.1.0"
31
+ "@object-ui/auth": "6.2.0",
32
+ "@object-ui/collaboration": "6.2.0",
33
+ "@object-ui/components": "6.2.0",
34
+ "@object-ui/plugin-editor": "6.2.0",
35
+ "@object-ui/core": "6.2.0",
36
+ "@object-ui/data-objectstack": "6.2.0",
37
+ "@object-ui/fields": "6.2.0",
38
+ "@object-ui/i18n": "6.2.0",
39
+ "@object-ui/layout": "6.2.0",
40
+ "@object-ui/permissions": "6.2.0",
41
+ "@object-ui/providers": "6.2.0",
42
+ "@object-ui/react": "6.2.0",
43
+ "@object-ui/types": "6.2.0"
43
44
  },
44
45
  "peerDependencies": {
45
46
  "react": "^18.0.0 || ^19.0.0",
46
47
  "react-dom": "^18.0.0 || ^19.0.0",
47
48
  "react-router-dom": "^6.0.0 || ^7.0.0",
48
- "@object-ui/plugin-calendar": "^6.1.0",
49
- "@object-ui/plugin-charts": "^6.1.0",
50
- "@object-ui/plugin-chatbot": "^6.1.0",
51
- "@object-ui/plugin-dashboard": "^6.1.0",
52
- "@object-ui/plugin-designer": "^6.1.0",
53
- "@object-ui/plugin-detail": "^6.1.0",
54
- "@object-ui/plugin-form": "^6.1.0",
55
- "@object-ui/plugin-grid": "^6.1.0",
56
- "@object-ui/plugin-kanban": "^6.1.0",
57
- "@object-ui/plugin-list": "^6.1.0",
58
- "@object-ui/plugin-report": "^6.1.0",
59
- "@object-ui/plugin-view": "^6.1.0"
49
+ "@object-ui/plugin-calendar": "^6.2.0",
50
+ "@object-ui/plugin-charts": "^6.2.0",
51
+ "@object-ui/plugin-chatbot": "^6.2.0",
52
+ "@object-ui/plugin-dashboard": "^6.2.0",
53
+ "@object-ui/plugin-designer": "^6.2.0",
54
+ "@object-ui/plugin-detail": "^6.2.0",
55
+ "@object-ui/plugin-form": "^6.2.0",
56
+ "@object-ui/plugin-grid": "^6.2.0",
57
+ "@object-ui/plugin-kanban": "^6.2.0",
58
+ "@object-ui/plugin-list": "^6.2.0",
59
+ "@object-ui/plugin-report": "^6.2.0",
60
+ "@object-ui/plugin-view": "^6.2.0"
60
61
  },
61
62
  "devDependencies": {
62
63
  "@types/node": "^25.9.1",