autoui-react 0.0.5-alpha → 0.1.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.
- package/README.md +6 -52
- package/dist/index.css +0 -10
- package/dist/index.css.map +1 -1
- package/dist/index.d.mts +87 -140
- package/dist/index.d.ts +87 -140
- package/dist/index.js +504 -2511
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +496 -2471
- package/dist/index.mjs.map +1 -1
- package/package.json +9 -48
package/dist/index.js
CHANGED
|
@@ -1,142 +1,26 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
var tailwindMerge = require('tailwind-merge');
|
|
5
|
-
var reactSlot = require('@radix-ui/react-slot');
|
|
6
|
-
var classVarianceAuthority = require('class-variance-authority');
|
|
7
|
-
var jsxRuntime = require('react/jsx-runtime');
|
|
8
|
-
var React = require('react');
|
|
9
|
-
var openai = require('@ai-sdk/openai');
|
|
10
|
-
var ai = require('ai');
|
|
3
|
+
var react = require('react');
|
|
11
4
|
var zod = require('zod');
|
|
12
|
-
var
|
|
13
|
-
var lucideReact = require('lucide-react');
|
|
14
|
-
var SelectPrimitive = require('@radix-ui/react-select');
|
|
15
|
-
var CheckboxPrimitive = require('@radix-ui/react-checkbox');
|
|
16
|
-
var RadioGroupPrimitive = require('@radix-ui/react-radio-group');
|
|
17
|
-
var TabsPrimitive = require('@radix-ui/react-tabs');
|
|
18
|
-
var LabelPrimitive = require('@radix-ui/react-label');
|
|
19
|
-
|
|
20
|
-
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
21
|
-
|
|
22
|
-
function _interopNamespace(e) {
|
|
23
|
-
if (e && e.__esModule) return e;
|
|
24
|
-
var n = Object.create(null);
|
|
25
|
-
if (e) {
|
|
26
|
-
Object.keys(e).forEach(function (k) {
|
|
27
|
-
if (k !== 'default') {
|
|
28
|
-
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
29
|
-
Object.defineProperty(n, k, d.get ? d : {
|
|
30
|
-
enumerable: true,
|
|
31
|
-
get: function () { return e[k]; }
|
|
32
|
-
});
|
|
33
|
-
}
|
|
34
|
-
});
|
|
35
|
-
}
|
|
36
|
-
n.default = e;
|
|
37
|
-
return Object.freeze(n);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
var React__default = /*#__PURE__*/_interopDefault(React);
|
|
41
|
-
var DialogPrimitive__namespace = /*#__PURE__*/_interopNamespace(DialogPrimitive);
|
|
42
|
-
var SelectPrimitive__namespace = /*#__PURE__*/_interopNamespace(SelectPrimitive);
|
|
43
|
-
var CheckboxPrimitive__namespace = /*#__PURE__*/_interopNamespace(CheckboxPrimitive);
|
|
44
|
-
var RadioGroupPrimitive__namespace = /*#__PURE__*/_interopNamespace(RadioGroupPrimitive);
|
|
45
|
-
var TabsPrimitive__namespace = /*#__PURE__*/_interopNamespace(TabsPrimitive);
|
|
46
|
-
var LabelPrimitive__namespace = /*#__PURE__*/_interopNamespace(LabelPrimitive);
|
|
47
|
-
|
|
48
|
-
var __defProp = Object.defineProperty;
|
|
49
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
50
|
-
var __esm = (fn, res) => function __init() {
|
|
51
|
-
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
52
|
-
};
|
|
53
|
-
var __export = (target, all) => {
|
|
54
|
-
for (var name in all)
|
|
55
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
56
|
-
};
|
|
57
|
-
function cn(...inputs) {
|
|
58
|
-
return tailwindMerge.twMerge(clsx.clsx(inputs));
|
|
59
|
-
}
|
|
60
|
-
var init_utils = __esm({
|
|
61
|
-
"src/lib/utils.ts"() {
|
|
62
|
-
}
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
// components/ui/button.tsx
|
|
66
|
-
var button_exports = {};
|
|
67
|
-
__export(button_exports, {
|
|
68
|
-
Button: () => Button2,
|
|
69
|
-
buttonVariants: () => buttonVariants
|
|
70
|
-
});
|
|
71
|
-
function Button2({
|
|
72
|
-
className,
|
|
73
|
-
variant,
|
|
74
|
-
size,
|
|
75
|
-
asChild = false,
|
|
76
|
-
...props
|
|
77
|
-
}) {
|
|
78
|
-
const Comp = asChild ? reactSlot.Slot : "button";
|
|
79
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
80
|
-
Comp,
|
|
81
|
-
{
|
|
82
|
-
"data-slot": "button",
|
|
83
|
-
className: cn(buttonVariants({ variant, size, className })),
|
|
84
|
-
...props
|
|
85
|
-
}
|
|
86
|
-
);
|
|
87
|
-
}
|
|
88
|
-
var buttonVariants;
|
|
89
|
-
var init_button = __esm({
|
|
90
|
-
"components/ui/button.tsx"() {
|
|
91
|
-
init_utils();
|
|
92
|
-
buttonVariants = classVarianceAuthority.cva(
|
|
93
|
-
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
|
|
94
|
-
{
|
|
95
|
-
variants: {
|
|
96
|
-
variant: {
|
|
97
|
-
default: "bg-primary text-primary-foreground shadow-xs hover:bg-primary/90",
|
|
98
|
-
destructive: "bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
|
|
99
|
-
outline: "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
|
|
100
|
-
secondary: "bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80",
|
|
101
|
-
ghost: "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
|
|
102
|
-
link: "text-primary underline-offset-4 hover:underline"
|
|
103
|
-
},
|
|
104
|
-
size: {
|
|
105
|
-
default: "h-9 px-4 py-2 has-[>svg]:px-3",
|
|
106
|
-
sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",
|
|
107
|
-
lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
|
|
108
|
-
icon: "size-9"
|
|
109
|
-
}
|
|
110
|
-
},
|
|
111
|
-
defaultVariants: {
|
|
112
|
-
variant: "default",
|
|
113
|
-
size: "default"
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
);
|
|
117
|
-
}
|
|
118
|
-
});
|
|
5
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
119
6
|
|
|
120
7
|
// src/core/reducer.ts
|
|
121
8
|
function cloneNode(node) {
|
|
122
9
|
return {
|
|
123
10
|
...node,
|
|
124
|
-
props: node.props ? { ...node.props } :
|
|
125
|
-
bindings: node.bindings ? { ...node.bindings } :
|
|
126
|
-
events: node.events ? { ...node.events } :
|
|
127
|
-
children: node.children
|
|
11
|
+
props: node.props ? { ...node.props } : void 0,
|
|
12
|
+
bindings: node.bindings ? { ...node.bindings } : void 0,
|
|
13
|
+
events: node.events ? { ...node.events } : void 0,
|
|
14
|
+
children: node.children?.map((child) => cloneNode(child))
|
|
128
15
|
};
|
|
129
16
|
}
|
|
130
17
|
function findNodeById(tree, nodeId) {
|
|
131
|
-
if (!tree)
|
|
132
|
-
|
|
133
|
-
if (tree.id === nodeId)
|
|
134
|
-
return tree;
|
|
18
|
+
if (!tree) return void 0;
|
|
19
|
+
if (tree.id === nodeId) return tree;
|
|
135
20
|
if (tree.children) {
|
|
136
21
|
for (const child of tree.children) {
|
|
137
22
|
const found = findNodeById(child, nodeId);
|
|
138
|
-
if (found)
|
|
139
|
-
return found;
|
|
23
|
+
if (found) return found;
|
|
140
24
|
}
|
|
141
25
|
}
|
|
142
26
|
return void 0;
|
|
@@ -151,15 +35,13 @@ function updateNodeById(tree, nodeId, updater) {
|
|
|
151
35
|
if (node.children) {
|
|
152
36
|
for (const child of node.children) {
|
|
153
37
|
const path2 = findPath(child, id, newPath);
|
|
154
|
-
if (path2)
|
|
155
|
-
return path2;
|
|
38
|
+
if (path2) return path2;
|
|
156
39
|
}
|
|
157
40
|
}
|
|
158
41
|
return null;
|
|
159
42
|
}
|
|
160
43
|
const path = findPath(result, nodeId);
|
|
161
|
-
if (!path)
|
|
162
|
-
return result;
|
|
44
|
+
if (!path) return result;
|
|
163
45
|
const nodeToUpdate = path[path.length - 1];
|
|
164
46
|
const updatedNode = updater(nodeToUpdate);
|
|
165
47
|
if (path.length === 1) {
|
|
@@ -168,14 +50,18 @@ function updateNodeById(tree, nodeId, updater) {
|
|
|
168
50
|
const parent = path[path.length - 2];
|
|
169
51
|
const updatedParent = {
|
|
170
52
|
...parent,
|
|
171
|
-
children: parent.children
|
|
53
|
+
children: parent.children?.map(
|
|
172
54
|
(child) => child.id === nodeId ? updatedNode : child
|
|
173
|
-
)
|
|
55
|
+
)
|
|
174
56
|
};
|
|
175
57
|
if (path.length === 2) {
|
|
176
58
|
return updatedParent;
|
|
177
59
|
}
|
|
178
|
-
return updateNodeById(
|
|
60
|
+
return updateNodeById(
|
|
61
|
+
result,
|
|
62
|
+
parent.id,
|
|
63
|
+
() => updatedParent
|
|
64
|
+
);
|
|
179
65
|
}
|
|
180
66
|
function replaceNodeById(tree, nodeId, newNode) {
|
|
181
67
|
return updateNodeById(tree, nodeId, () => newNode);
|
|
@@ -202,8 +88,7 @@ function removeNodeById(tree, nodeId) {
|
|
|
202
88
|
}
|
|
203
89
|
for (const child of node.children) {
|
|
204
90
|
const parent2 = findParent(child, id);
|
|
205
|
-
if (parent2)
|
|
206
|
-
return parent2;
|
|
91
|
+
if (parent2) return parent2;
|
|
207
92
|
}
|
|
208
93
|
}
|
|
209
94
|
return null;
|
|
@@ -213,11 +98,10 @@ function removeNodeById(tree, nodeId) {
|
|
|
213
98
|
throw new Error("Cannot remove root node");
|
|
214
99
|
}
|
|
215
100
|
const parent = findParent(result, nodeId);
|
|
216
|
-
if (!parent)
|
|
217
|
-
return result;
|
|
101
|
+
if (!parent) return result;
|
|
218
102
|
return updateNodeById(result, parent.id, (node) => ({
|
|
219
103
|
...node,
|
|
220
|
-
children: node.children
|
|
104
|
+
children: node.children?.filter((child) => child.id !== nodeId)
|
|
221
105
|
}));
|
|
222
106
|
}
|
|
223
107
|
function uiReducer(state, action) {
|
|
@@ -234,7 +118,7 @@ function uiReducer(state, action) {
|
|
|
234
118
|
...state,
|
|
235
119
|
layout: action.node,
|
|
236
120
|
loading: false,
|
|
237
|
-
error:
|
|
121
|
+
error: void 0
|
|
238
122
|
};
|
|
239
123
|
}
|
|
240
124
|
case "PARTIAL_UPDATE": {
|
|
@@ -243,7 +127,7 @@ function uiReducer(state, action) {
|
|
|
243
127
|
...state,
|
|
244
128
|
layout: action.node,
|
|
245
129
|
loading: false,
|
|
246
|
-
error:
|
|
130
|
+
error: void 0
|
|
247
131
|
};
|
|
248
132
|
}
|
|
249
133
|
if (action.nodeId === "root" || action.nodeId === state.layout.id) {
|
|
@@ -251,23 +135,19 @@ function uiReducer(state, action) {
|
|
|
251
135
|
...state,
|
|
252
136
|
layout: action.node,
|
|
253
137
|
loading: false,
|
|
254
|
-
error:
|
|
138
|
+
error: void 0
|
|
255
139
|
};
|
|
256
140
|
}
|
|
257
141
|
return {
|
|
258
142
|
...state,
|
|
259
143
|
layout: replaceNodeById(state.layout, action.nodeId, action.node),
|
|
260
144
|
loading: false,
|
|
261
|
-
error:
|
|
145
|
+
error: void 0
|
|
262
146
|
};
|
|
263
147
|
}
|
|
264
148
|
case "ADD_NODE": {
|
|
265
149
|
if (!state.layout) {
|
|
266
|
-
return
|
|
267
|
-
...state,
|
|
268
|
-
error: "Cannot add node: Layout is empty.",
|
|
269
|
-
loading: false
|
|
270
|
-
};
|
|
150
|
+
return state;
|
|
271
151
|
}
|
|
272
152
|
return {
|
|
273
153
|
...state,
|
|
@@ -275,41 +155,21 @@ function uiReducer(state, action) {
|
|
|
275
155
|
state.layout,
|
|
276
156
|
action.parentId,
|
|
277
157
|
action.node,
|
|
278
|
-
action.index
|
|
158
|
+
action.index
|
|
279
159
|
),
|
|
280
160
|
loading: false,
|
|
281
|
-
error:
|
|
161
|
+
error: void 0
|
|
282
162
|
};
|
|
283
163
|
}
|
|
284
164
|
case "REMOVE_NODE": {
|
|
285
165
|
if (!state.layout) {
|
|
286
|
-
return
|
|
287
|
-
...state,
|
|
288
|
-
error: "Cannot remove node: Layout is empty.",
|
|
289
|
-
loading: false
|
|
290
|
-
};
|
|
291
|
-
}
|
|
292
|
-
try {
|
|
293
|
-
return {
|
|
294
|
-
...state,
|
|
295
|
-
layout: removeNodeById(state.layout, action.nodeId),
|
|
296
|
-
loading: false,
|
|
297
|
-
error: null
|
|
298
|
-
};
|
|
299
|
-
} catch (e) {
|
|
300
|
-
const errorMessage = e instanceof Error ? e.message : "Failed to remove node.";
|
|
301
|
-
return {
|
|
302
|
-
...state,
|
|
303
|
-
error: errorMessage,
|
|
304
|
-
loading: false
|
|
305
|
-
};
|
|
166
|
+
return state;
|
|
306
167
|
}
|
|
307
|
-
}
|
|
308
|
-
case "ERROR": {
|
|
309
168
|
return {
|
|
310
169
|
...state,
|
|
311
|
-
|
|
312
|
-
loading: false
|
|
170
|
+
layout: removeNodeById(state.layout, action.nodeId),
|
|
171
|
+
loading: false,
|
|
172
|
+
error: void 0
|
|
313
173
|
};
|
|
314
174
|
}
|
|
315
175
|
case "LOADING": {
|
|
@@ -318,84 +178,23 @@ function uiReducer(state, action) {
|
|
|
318
178
|
loading: action.isLoading
|
|
319
179
|
};
|
|
320
180
|
}
|
|
181
|
+
case "ERROR": {
|
|
182
|
+
return {
|
|
183
|
+
...state,
|
|
184
|
+
error: action.message,
|
|
185
|
+
loading: false
|
|
186
|
+
};
|
|
187
|
+
}
|
|
321
188
|
default:
|
|
322
189
|
return state;
|
|
323
190
|
}
|
|
324
191
|
}
|
|
325
192
|
var initialState = {
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
history: [],
|
|
329
|
-
error: null
|
|
193
|
+
loading: true,
|
|
194
|
+
history: []
|
|
330
195
|
};
|
|
331
196
|
|
|
332
197
|
// src/core/action-router.ts
|
|
333
|
-
var UI_GUIDANCE_BASE = `
|
|
334
|
-
UI Guidance:
|
|
335
|
-
1. Create a focused interface that directly addresses the goal
|
|
336
|
-
2. Use appropriate UI patterns (lists, forms, details, etc.)
|
|
337
|
-
3. Include navigation between related views when needed
|
|
338
|
-
4. Keep the interface simple and intuitive
|
|
339
|
-
5. Bind to schema data where appropriate
|
|
340
|
-
6. Provide event handlers for user interactions - make sure to always include both action and target properties`;
|
|
341
|
-
var LIST_BINDING_GUIDANCE = `7. **CRITICAL:** For \`ListView\` or \`Table\` nodes, the \`data\` binding key **MUST** point to the *exact path* of the data *array* within the context.`;
|
|
342
|
-
var LIST_BINDING_EXAMPLE = `Example: If the context has \`{ tasks: { data: [...] } }\`, the binding **MUST** be \`{ "bindings": { "data": "tasks.data" } }\`. If the context has \`{ userList: [...] }\`, the binding **MUST** be \`{ "bindings": { "data": "userList" } }\`. **NEVER** bind to the parent object containing the array (e.g., DO NOT USE \`{ "bindings": { "data": "tasks" } }\`).`;
|
|
343
|
-
var COMMON_UI_GUIDANCE = UI_GUIDANCE_BASE + "\n" + // Add a newline separator
|
|
344
|
-
LIST_BINDING_GUIDANCE + // Add the specific list binding rule
|
|
345
|
-
"\n" + // Add a newline separator
|
|
346
|
-
LIST_BINDING_EXAMPLE;
|
|
347
|
-
function processTemplate(template, values) {
|
|
348
|
-
return template.replace(/\${(.*?)}/g, (match, key) => {
|
|
349
|
-
const trimmedKey = key.trim();
|
|
350
|
-
return trimmedKey in values ? String(values[trimmedKey]) : match;
|
|
351
|
-
});
|
|
352
|
-
}
|
|
353
|
-
function buildPrompt(input, promptTemplate, templateValues) {
|
|
354
|
-
const { schema, goal, history, userContext } = input;
|
|
355
|
-
const schemaInfo = Object.entries(schema).map(([tableName, tableSchema]) => {
|
|
356
|
-
const schemaString = typeof tableSchema === "object" && tableSchema !== null ? JSON.stringify(tableSchema) : String(tableSchema);
|
|
357
|
-
return `Table: ${tableName}
|
|
358
|
-
Schema: ${schemaString}`;
|
|
359
|
-
}).join("\n\n");
|
|
360
|
-
const recentEvents = history && history.length > 0 ? history.slice(-5).map(
|
|
361
|
-
(event) => `Event: ${event.type} on node ${event.nodeId}${event.payload ? ` with payload ${JSON.stringify(event.payload)}` : ""}`
|
|
362
|
-
).join("\n") : "No recent events";
|
|
363
|
-
const userContextSection = userContext ? `
|
|
364
|
-
|
|
365
|
-
User Context:
|
|
366
|
-
${JSON.stringify(userContext)}` : "";
|
|
367
|
-
if (promptTemplate && templateValues) {
|
|
368
|
-
const fullTemplateValues = {
|
|
369
|
-
...templateValues,
|
|
370
|
-
schemaInfo,
|
|
371
|
-
recentEvents,
|
|
372
|
-
userContextString: userContextSection.trim(),
|
|
373
|
-
// Use trimmed version
|
|
374
|
-
commonUIGuidance: COMMON_UI_GUIDANCE,
|
|
375
|
-
goal
|
|
376
|
-
// Ensure goal is always available to templates
|
|
377
|
-
};
|
|
378
|
-
return processTemplate(promptTemplate, fullTemplateValues);
|
|
379
|
-
}
|
|
380
|
-
const interactionDescription = history && history.length > 0 ? `The user's last action was: ${history[history.length - 1].type} on node ${history[history.length - 1].nodeId}` : "The user initiated the session for the goal";
|
|
381
|
-
return `
|
|
382
|
-
You are an expert UI generator.
|
|
383
|
-
Create a user interface that achieves the following goal: "${goal}".
|
|
384
|
-
${interactionDescription}.
|
|
385
|
-
|
|
386
|
-
Available data schema:
|
|
387
|
-
${schemaInfo}
|
|
388
|
-
|
|
389
|
-
Recent user interactions:
|
|
390
|
-
${recentEvents}${userContextSection}
|
|
391
|
-
|
|
392
|
-
Generate a complete UI specification in JSON format that matches the following TypeScript type:
|
|
393
|
-
type UISpecNode = { id: string; node_type: string; props?: Record<string, unknown>; bindings?: Record<string, unknown>; events?: Record<string, { action: string; target: string; payload?: Record<string, unknown>; }>; children?: UISpecNode[]; };
|
|
394
|
-
${COMMON_UI_GUIDANCE}
|
|
395
|
-
|
|
396
|
-
Respond ONLY with the JSON UI specification and no other text.
|
|
397
|
-
`;
|
|
398
|
-
}
|
|
399
198
|
var ActionType = /* @__PURE__ */ ((ActionType2) => {
|
|
400
199
|
ActionType2["FULL_REFRESH"] = "FULL_REFRESH";
|
|
401
200
|
ActionType2["UPDATE_NODE"] = "UPDATE_NODE";
|
|
@@ -430,39 +229,19 @@ var ActionRouter = class {
|
|
|
430
229
|
* @returns Route resolution or null if no match
|
|
431
230
|
*/
|
|
432
231
|
resolveRoute(event, schema, layout, dataContext, goal, userContext) {
|
|
433
|
-
console.log(
|
|
434
|
-
`[ActionRouter Debug] resolveRoute called for event type: ${event.type}`
|
|
435
|
-
);
|
|
436
232
|
const routes = this.routes[event.type] || [];
|
|
437
|
-
console.log(
|
|
438
|
-
`[ActionRouter Debug] Found ${routes.length} routes for ${event.type}`
|
|
439
|
-
);
|
|
440
233
|
if (routes.length === 0) {
|
|
441
|
-
|
|
442
|
-
`[ActionRouter Debug] No specific route found for ${event.type}, using default FULL_REFRESH.`
|
|
443
|
-
);
|
|
444
|
-
const defaultPlannerInput = {
|
|
445
|
-
schema,
|
|
446
|
-
goal,
|
|
447
|
-
history: [event],
|
|
448
|
-
userContext: userContext || null
|
|
449
|
-
};
|
|
450
|
-
const defaultPrompt = buildPrompt(
|
|
451
|
-
defaultPlannerInput,
|
|
452
|
-
void 0,
|
|
453
|
-
void 0
|
|
454
|
-
);
|
|
455
|
-
const defaultResolution = {
|
|
234
|
+
return {
|
|
456
235
|
actionType: "FULL_REFRESH" /* FULL_REFRESH */,
|
|
457
236
|
targetNodeId: layout?.id || "root",
|
|
458
|
-
plannerInput:
|
|
459
|
-
|
|
237
|
+
plannerInput: {
|
|
238
|
+
schema,
|
|
239
|
+
goal,
|
|
240
|
+
history: [event],
|
|
241
|
+
userContext
|
|
242
|
+
},
|
|
243
|
+
prompt: `Generate a new UI for the goal: "${goal}". The user just triggered: ${event.type} on node ${event.nodeId}`
|
|
460
244
|
};
|
|
461
|
-
console.log(
|
|
462
|
-
"[ActionRouter Debug] Default Resolution:",
|
|
463
|
-
defaultResolution
|
|
464
|
-
);
|
|
465
|
-
return defaultResolution;
|
|
466
245
|
}
|
|
467
246
|
const sourceNode = layout ? findNodeById(layout, event.nodeId) : void 0;
|
|
468
247
|
const nodeConfig = sourceNode?.events?.[event.type];
|
|
@@ -475,7 +254,6 @@ var ActionRouter = class {
|
|
|
475
254
|
if (!matchingRoute) {
|
|
476
255
|
matchingRoute = routes[0];
|
|
477
256
|
}
|
|
478
|
-
console.log("[ActionRouter Debug] Matching Route Config:", matchingRoute);
|
|
479
257
|
const targetNodeId = nodeConfig?.target || matchingRoute.targetNodeId || event.nodeId;
|
|
480
258
|
const additionalContext = {};
|
|
481
259
|
if (matchingRoute.contextKeys) {
|
|
@@ -509,35 +287,23 @@ var ActionRouter = class {
|
|
|
509
287
|
...additionalContext
|
|
510
288
|
}
|
|
511
289
|
};
|
|
512
|
-
const
|
|
513
|
-
goal,
|
|
514
|
-
eventType: event.type,
|
|
515
|
-
nodeId: event.nodeId,
|
|
516
|
-
targetNodeId,
|
|
517
|
-
actionType: matchingRoute.actionType,
|
|
518
|
-
...userContext || {},
|
|
519
|
-
// Spread the original userContext (passed to resolveRoute)
|
|
520
|
-
...additionalContext
|
|
521
|
-
// Spread additionalContext afterwards (can override userContext keys)
|
|
522
|
-
};
|
|
523
|
-
console.log("[ActionRouter Debug] Template Values:", templateValues);
|
|
524
|
-
const finalPrompt = buildPrompt(
|
|
525
|
-
plannerInput2,
|
|
290
|
+
const prompt = this.processTemplate(
|
|
526
291
|
matchingRoute.promptTemplate,
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
292
|
+
{
|
|
293
|
+
goal,
|
|
294
|
+
eventType: event.type,
|
|
295
|
+
nodeId: event.nodeId,
|
|
296
|
+
targetNodeId,
|
|
297
|
+
actionType: matchingRoute.actionType,
|
|
298
|
+
...additionalContext
|
|
299
|
+
}
|
|
530
300
|
);
|
|
531
|
-
|
|
532
|
-
const finalResolution = {
|
|
301
|
+
return {
|
|
533
302
|
actionType: matchingRoute.actionType,
|
|
534
303
|
targetNodeId,
|
|
535
304
|
plannerInput: plannerInput2,
|
|
536
|
-
prompt
|
|
537
|
-
// Use the generated prompt
|
|
305
|
+
prompt
|
|
538
306
|
};
|
|
539
|
-
console.log("[ActionRouter Debug] Final Resolution:", finalResolution);
|
|
540
|
-
return finalResolution;
|
|
541
307
|
}
|
|
542
308
|
/**
|
|
543
309
|
* Process a prompt template with variables
|
|
@@ -555,11 +321,8 @@ function createDefaultRouter() {
|
|
|
555
321
|
const router = new ActionRouter();
|
|
556
322
|
router.registerRoute("CLICK", {
|
|
557
323
|
actionType: "FULL_REFRESH" /* FULL_REFRESH */,
|
|
558
|
-
targetNodeId: "root"
|
|
559
|
-
|
|
560
|
-
router.registerRoute("INIT", {
|
|
561
|
-
actionType: "FULL_REFRESH" /* FULL_REFRESH */,
|
|
562
|
-
targetNodeId: "root"
|
|
324
|
+
targetNodeId: "root",
|
|
325
|
+
promptTemplate: 'Generate a new UI for the goal: "${goal}". The user just clicked on node ${nodeId}'
|
|
563
326
|
});
|
|
564
327
|
router.registerRoute("CLICK", {
|
|
565
328
|
actionType: "SHOW_DETAIL" /* SHOW_DETAIL */,
|
|
@@ -589,31 +352,7 @@ function createDefaultRouter() {
|
|
|
589
352
|
});
|
|
590
353
|
return router;
|
|
591
354
|
}
|
|
592
|
-
var componentType = zod.z.enum([
|
|
593
|
-
// Layout components
|
|
594
|
-
"Container",
|
|
595
|
-
"Card",
|
|
596
|
-
"Header",
|
|
597
|
-
// Input components
|
|
598
|
-
"Button",
|
|
599
|
-
"Input",
|
|
600
|
-
"Select",
|
|
601
|
-
"Textarea",
|
|
602
|
-
"Checkbox",
|
|
603
|
-
"RadioGroup",
|
|
604
|
-
// Data display components
|
|
605
|
-
"ListView",
|
|
606
|
-
"Detail",
|
|
607
|
-
"Tabs",
|
|
608
|
-
"Dialog",
|
|
609
|
-
// Typography
|
|
610
|
-
"Heading",
|
|
611
|
-
"Text"
|
|
612
|
-
]);
|
|
613
|
-
|
|
614
|
-
// src/schema/ui.ts
|
|
615
355
|
var uiEventType = zod.z.enum([
|
|
616
|
-
"INIT",
|
|
617
356
|
"CLICK",
|
|
618
357
|
"CHANGE",
|
|
619
358
|
"SUBMIT",
|
|
@@ -625,62 +364,27 @@ var uiEventType = zod.z.enum([
|
|
|
625
364
|
var uiEvent = zod.z.object({
|
|
626
365
|
type: uiEventType,
|
|
627
366
|
nodeId: zod.z.string(),
|
|
628
|
-
timestamp: zod.z.number().
|
|
629
|
-
payload: zod.z.record(zod.z.
|
|
630
|
-
});
|
|
631
|
-
zod.z.enum(["AI_RESPONSE", "ERROR"]);
|
|
632
|
-
var runtimeRecord = zod.z.record(zod.z.any()).nullable();
|
|
633
|
-
var openAISimplifiedValue = zod.z.string().nullable();
|
|
634
|
-
var openAIRecordSimplifiedNullable = zod.z.record(openAISimplifiedValue).nullable();
|
|
635
|
-
var openAIEventPayloadSimplifiedNullable = zod.z.record(openAISimplifiedValue).nullable();
|
|
636
|
-
var openAIBaseNode = zod.z.object({
|
|
637
|
-
id: zod.z.string().describe("Unique identifier for the UI node."),
|
|
638
|
-
node_type: componentType.describe(
|
|
639
|
-
"The type of UI component (e.g., Container, Text, Button, ListView)."
|
|
640
|
-
),
|
|
641
|
-
props: openAIRecordSimplifiedNullable.describe(
|
|
642
|
-
'Component-specific properties (attributes). Values should be strings or null. E.g., for Header use { "title": "My Title" }; for Text use { "text": "My Text" }.'
|
|
643
|
-
),
|
|
644
|
-
bindings: openAIRecordSimplifiedNullable.describe(
|
|
645
|
-
'Data bindings map context paths to component props. Values are paths (e.g., "user.name") or templates (e.g., "{{item.title}}"). **CRITICAL for ListView/Table:** the `data` key MUST point to the *exact array path* (e.g., { "data": "tasks.data" } or { "data": "userList" }), NOT the parent object.'
|
|
646
|
-
),
|
|
647
|
-
events: zod.z.record(
|
|
648
|
-
zod.z.string(),
|
|
649
|
-
zod.z.object({
|
|
650
|
-
action: zod.z.string(),
|
|
651
|
-
target: zod.z.string(),
|
|
652
|
-
payload: openAIEventPayloadSimplifiedNullable
|
|
653
|
-
})
|
|
654
|
-
).nullable(),
|
|
655
|
-
// Entire events object is nullable
|
|
656
|
-
children: zod.z.null()
|
|
657
|
-
// Base children are null. When extended, it will be an array or null.
|
|
658
|
-
});
|
|
659
|
-
var openAINodeL4 = openAIBaseNode;
|
|
660
|
-
var openAINodeL3 = openAIBaseNode.extend({
|
|
661
|
-
children: zod.z.array(openAINodeL4).nullable()
|
|
662
|
-
});
|
|
663
|
-
var openAINodeL2 = openAIBaseNode.extend({
|
|
664
|
-
children: zod.z.array(openAINodeL3).nullable()
|
|
367
|
+
timestamp: zod.z.number().optional(),
|
|
368
|
+
payload: zod.z.record(zod.z.any()).optional()
|
|
665
369
|
});
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
370
|
+
zod.z.enum([
|
|
371
|
+
"AI_RESPONSE",
|
|
372
|
+
"ERROR"
|
|
373
|
+
]);
|
|
374
|
+
var uiSpecNode = zod.z.lazy(() => zod.z.object({
|
|
670
375
|
id: zod.z.string(),
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
).
|
|
682
|
-
|
|
683
|
-
});
|
|
376
|
+
type: zod.z.string(),
|
|
377
|
+
// e.g., "ListView", "Button", "TextField"
|
|
378
|
+
props: zod.z.record(zod.z.any()).optional(),
|
|
379
|
+
bindings: zod.z.record(zod.z.any()).optional(),
|
|
380
|
+
// Data bindings
|
|
381
|
+
events: zod.z.record(zod.z.string(), zod.z.object({
|
|
382
|
+
action: zod.z.string(),
|
|
383
|
+
target: zod.z.string().optional(),
|
|
384
|
+
payload: zod.z.record(zod.z.any()).optional()
|
|
385
|
+
})).optional(),
|
|
386
|
+
children: zod.z.array(uiSpecNode).optional()
|
|
387
|
+
}));
|
|
684
388
|
zod.z.discriminatedUnion("type", [
|
|
685
389
|
zod.z.object({
|
|
686
390
|
type: zod.z.literal("UI_EVENT"),
|
|
@@ -699,7 +403,7 @@ zod.z.discriminatedUnion("type", [
|
|
|
699
403
|
type: zod.z.literal("ADD_NODE"),
|
|
700
404
|
parentId: zod.z.string(),
|
|
701
405
|
node: uiSpecNode,
|
|
702
|
-
index: zod.z.number().
|
|
406
|
+
index: zod.z.number().optional()
|
|
703
407
|
}),
|
|
704
408
|
zod.z.object({
|
|
705
409
|
type: zod.z.literal("REMOVE_NODE"),
|
|
@@ -715,16 +419,16 @@ zod.z.discriminatedUnion("type", [
|
|
|
715
419
|
})
|
|
716
420
|
]);
|
|
717
421
|
zod.z.object({
|
|
718
|
-
layout: uiSpecNode.
|
|
422
|
+
layout: uiSpecNode.optional(),
|
|
719
423
|
loading: zod.z.boolean(),
|
|
720
424
|
history: zod.z.array(uiEvent),
|
|
721
|
-
error: zod.z.string().
|
|
425
|
+
error: zod.z.string().optional()
|
|
722
426
|
});
|
|
723
427
|
zod.z.object({
|
|
724
428
|
schema: zod.z.record(zod.z.unknown()),
|
|
725
429
|
goal: zod.z.string(),
|
|
726
|
-
history: zod.z.array(uiEvent).
|
|
727
|
-
userContext: zod.z.record(zod.z.unknown()).
|
|
430
|
+
history: zod.z.array(uiEvent).optional(),
|
|
431
|
+
userContext: zod.z.record(zod.z.unknown()).optional()
|
|
728
432
|
});
|
|
729
433
|
|
|
730
434
|
// src/core/system-events.ts
|
|
@@ -750,7 +454,7 @@ var SystemEventManager = class {
|
|
|
750
454
|
}
|
|
751
455
|
/**
|
|
752
456
|
* Register a listener for a specific system event type
|
|
753
|
-
*
|
|
457
|
+
*
|
|
754
458
|
* @param eventType - The system event type to listen for
|
|
755
459
|
* @param listener - The listener function
|
|
756
460
|
* @returns Function to unregister the listener
|
|
@@ -770,7 +474,7 @@ var SystemEventManager = class {
|
|
|
770
474
|
}
|
|
771
475
|
/**
|
|
772
476
|
* Emit a system event to all registered listeners
|
|
773
|
-
*
|
|
477
|
+
*
|
|
774
478
|
* @param event - The system event to emit
|
|
775
479
|
*/
|
|
776
480
|
async emit(event) {
|
|
@@ -790,917 +494,257 @@ function createSystemEvent(type, data) {
|
|
|
790
494
|
}
|
|
791
495
|
|
|
792
496
|
// src/env.ts
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
//
|
|
797
|
-
|
|
798
|
-
// Simplified NODE_ENV assignment
|
|
799
|
-
OPENAI_API_KEY: rawApiKeyFromEnv || ""
|
|
800
|
-
};
|
|
497
|
+
({
|
|
498
|
+
MOCK_PLANNER: undefined?.VITE_MOCK_PLANNER || "1",
|
|
499
|
+
NODE_ENV: undefined?.MODE || "development"
|
|
500
|
+
// Add other environment variables as needed
|
|
501
|
+
});
|
|
801
502
|
|
|
802
503
|
// src/core/planner.ts
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
});
|
|
504
|
+
function buildPrompt(input, targetNodeId, customPrompt) {
|
|
505
|
+
const { schema, goal, history, userContext } = input;
|
|
506
|
+
const schemaInfo = Object.entries(schema).map(([tableName, tableSchema]) => {
|
|
507
|
+
return `Table: ${tableName}
|
|
508
|
+
Schema: ${JSON.stringify(tableSchema)}`;
|
|
509
|
+
}).join("\n\n");
|
|
510
|
+
const recentEvents = history?.slice(-5).map(
|
|
511
|
+
(event) => `Event: ${event.type} on node ${event.nodeId}${event.payload ? ` with payload ${JSON.stringify(event.payload)}` : ""}`
|
|
512
|
+
).join("\n") || "No recent events";
|
|
513
|
+
const userContextSection = userContext ? `
|
|
514
|
+
|
|
515
|
+
User Context:
|
|
516
|
+
${JSON.stringify(userContext)}` : "";
|
|
517
|
+
return `
|
|
518
|
+
You are an expert UI generator.
|
|
519
|
+
Create a user interface that achieves the following goal: "${goal}"
|
|
520
|
+
|
|
521
|
+
Available data schema:
|
|
522
|
+
${schemaInfo}
|
|
523
|
+
|
|
524
|
+
Recent user interactions:
|
|
525
|
+
${recentEvents}${userContextSection}
|
|
526
|
+
|
|
527
|
+
Generate a complete UI specification in JSON format that matches the following TypeScript type:
|
|
528
|
+
type UISpecNode = {
|
|
529
|
+
id: string;
|
|
530
|
+
type: string;
|
|
531
|
+
props?: Record<string, any>;
|
|
532
|
+
bindings?: Record<string, any>;
|
|
533
|
+
events?: Record<string, { action: string; target?: string; payload?: Record<string, any>; }>;
|
|
534
|
+
children?: UISpecNode[];
|
|
809
535
|
};
|
|
536
|
+
|
|
537
|
+
UI Guidance:
|
|
538
|
+
1. Create a focused interface that directly addresses the goal
|
|
539
|
+
2. Use appropriate UI patterns (lists, forms, details, etc.)
|
|
540
|
+
3. Include navigation between related views when needed
|
|
541
|
+
4. Keep the interface simple and intuitive
|
|
542
|
+
5. Bind to schema data where appropriate
|
|
543
|
+
6. Provide event handlers for user interactions
|
|
544
|
+
|
|
545
|
+
Respond ONLY with the JSON UI specification and no other text.
|
|
546
|
+
`;
|
|
547
|
+
}
|
|
810
548
|
function mockPlanner(input, targetNodeId, customPrompt) {
|
|
811
|
-
if (customPrompt) {
|
|
812
|
-
console.log("mockPlanner received customPrompt:", customPrompt);
|
|
813
|
-
}
|
|
814
|
-
const taskSchema = input.schema.tasks;
|
|
815
|
-
const taskData = taskSchema?.sampleData || [
|
|
816
|
-
{
|
|
817
|
-
id: "1",
|
|
818
|
-
title: "Example Task 1",
|
|
819
|
-
description: "This is a sample task",
|
|
820
|
-
status: "pending",
|
|
821
|
-
priority: "medium"
|
|
822
|
-
},
|
|
823
|
-
{
|
|
824
|
-
id: "2",
|
|
825
|
-
title: "Example Task 2",
|
|
826
|
-
description: "Another sample task",
|
|
827
|
-
status: "completed",
|
|
828
|
-
priority: "high"
|
|
829
|
-
}
|
|
830
|
-
];
|
|
831
549
|
const mockNode = {
|
|
832
550
|
id: targetNodeId || "root",
|
|
833
|
-
|
|
834
|
-
props: {
|
|
835
|
-
className: "p-4 space-y-6"
|
|
836
|
-
},
|
|
837
|
-
bindings: null,
|
|
838
|
-
events: null,
|
|
551
|
+
type: "Container",
|
|
552
|
+
props: { title: "Mock UI" },
|
|
839
553
|
children: [
|
|
840
554
|
{
|
|
841
|
-
id: "
|
|
842
|
-
|
|
843
|
-
props: {
|
|
844
|
-
title: "Task Management Dashboard",
|
|
845
|
-
className: "mb-4"
|
|
846
|
-
},
|
|
847
|
-
bindings: null,
|
|
848
|
-
events: null,
|
|
849
|
-
children: null
|
|
850
|
-
},
|
|
851
|
-
{
|
|
852
|
-
id: "main-content",
|
|
853
|
-
node_type: "Container",
|
|
854
|
-
props: {
|
|
855
|
-
className: "grid grid-cols-1 gap-6 md:grid-cols-3"
|
|
856
|
-
},
|
|
857
|
-
bindings: null,
|
|
858
|
-
events: null,
|
|
859
|
-
children: [
|
|
860
|
-
{
|
|
861
|
-
id: "tasks-container",
|
|
862
|
-
node_type: "Container",
|
|
863
|
-
props: {
|
|
864
|
-
className: "md:col-span-2"
|
|
865
|
-
},
|
|
866
|
-
bindings: null,
|
|
867
|
-
events: null,
|
|
868
|
-
children: [
|
|
869
|
-
{
|
|
870
|
-
id: "list-heading",
|
|
871
|
-
node_type: "Container",
|
|
872
|
-
props: {
|
|
873
|
-
className: "flex justify-between items-center mb-4"
|
|
874
|
-
},
|
|
875
|
-
bindings: null,
|
|
876
|
-
events: null,
|
|
877
|
-
children: [
|
|
878
|
-
{
|
|
879
|
-
id: "list-title",
|
|
880
|
-
node_type: "Header",
|
|
881
|
-
props: {
|
|
882
|
-
title: "Tasks",
|
|
883
|
-
className: "border-none p-0 m-0"
|
|
884
|
-
},
|
|
885
|
-
bindings: null,
|
|
886
|
-
events: null,
|
|
887
|
-
children: null
|
|
888
|
-
},
|
|
889
|
-
{
|
|
890
|
-
id: "add-task-button",
|
|
891
|
-
node_type: "Button",
|
|
892
|
-
props: {
|
|
893
|
-
label: "Add Task",
|
|
894
|
-
variant: "default"
|
|
895
|
-
},
|
|
896
|
-
bindings: null,
|
|
897
|
-
events: {
|
|
898
|
-
onClick: {
|
|
899
|
-
action: "ADD_TASK",
|
|
900
|
-
target: "tasks-container",
|
|
901
|
-
payload: {}
|
|
902
|
-
}
|
|
903
|
-
},
|
|
904
|
-
children: null
|
|
905
|
-
}
|
|
906
|
-
]
|
|
907
|
-
},
|
|
908
|
-
{
|
|
909
|
-
id: "task-list",
|
|
910
|
-
node_type: "ListView",
|
|
911
|
-
props: {
|
|
912
|
-
selectable: "true"
|
|
913
|
-
},
|
|
914
|
-
bindings: {
|
|
915
|
-
data: "tasks.data",
|
|
916
|
-
fields: JSON.stringify([
|
|
917
|
-
{ key: "id", label: "ID" },
|
|
918
|
-
{ key: "title", label: "Title" },
|
|
919
|
-
{ key: "status", label: "Status" },
|
|
920
|
-
{ key: "priority", label: "Priority" }
|
|
921
|
-
])
|
|
922
|
-
},
|
|
923
|
-
events: {
|
|
924
|
-
onSelect: {
|
|
925
|
-
action: "SELECT_TASK",
|
|
926
|
-
target: "task-detail",
|
|
927
|
-
payload: {
|
|
928
|
-
source: "task-list"
|
|
929
|
-
}
|
|
930
|
-
}
|
|
931
|
-
},
|
|
932
|
-
children: null
|
|
933
|
-
}
|
|
934
|
-
]
|
|
935
|
-
},
|
|
936
|
-
{
|
|
937
|
-
id: "task-detail",
|
|
938
|
-
node_type: "Detail",
|
|
939
|
-
props: {
|
|
940
|
-
title: "Task Details",
|
|
941
|
-
visible: "true"
|
|
942
|
-
},
|
|
943
|
-
bindings: {
|
|
944
|
-
data: JSON.stringify(taskData[0]),
|
|
945
|
-
fields: JSON.stringify([
|
|
946
|
-
{ key: "title", label: "Title", type: "heading" },
|
|
947
|
-
{ key: "description", label: "Description", type: "content" },
|
|
948
|
-
{ key: "status", label: "Status" },
|
|
949
|
-
{ key: "priority", label: "Priority" },
|
|
950
|
-
{ key: "dueDate", label: "Due Date" }
|
|
951
|
-
])
|
|
952
|
-
},
|
|
953
|
-
events: {
|
|
954
|
-
onBack: {
|
|
955
|
-
action: "CLOSE_DETAIL",
|
|
956
|
-
target: "task-detail",
|
|
957
|
-
payload: {}
|
|
958
|
-
}
|
|
959
|
-
},
|
|
960
|
-
children: null
|
|
961
|
-
}
|
|
962
|
-
]
|
|
555
|
+
id: "text-1",
|
|
556
|
+
type: "Text",
|
|
557
|
+
props: { text: "This is a mock UI for testing" }
|
|
963
558
|
}
|
|
964
559
|
]
|
|
965
560
|
};
|
|
966
561
|
return mockNode;
|
|
967
562
|
}
|
|
968
|
-
async function callPlannerLLM(input, openaiApiKey, routeResolution) {
|
|
969
|
-
await systemEvents.emit(
|
|
970
|
-
createSystemEvent("PLAN_START" /* PLAN_START */, { plannerInput: input })
|
|
971
|
-
);
|
|
972
|
-
if (env.MOCK_PLANNER === "1") {
|
|
973
|
-
console.warn(
|
|
974
|
-
`Using mock planner because MOCK_PLANNER environment variable is set to "1".`
|
|
975
|
-
);
|
|
976
|
-
return mockPlanner(input);
|
|
977
|
-
}
|
|
978
|
-
if (!openaiApiKey) {
|
|
979
|
-
console.warn(
|
|
980
|
-
`OpenAI API key was not provided to callPlannerLLM. Falling back to mock planner.`
|
|
981
|
-
);
|
|
982
|
-
return mockPlanner(input);
|
|
983
|
-
}
|
|
984
|
-
const startTime = Date.now();
|
|
985
|
-
const prompt = routeResolution?.prompt;
|
|
986
|
-
if (!prompt) {
|
|
987
|
-
throw new Error("ActionRouter did not provide a prompt to callPlannerLLM.");
|
|
988
|
-
}
|
|
989
|
-
await systemEvents.emit(
|
|
990
|
-
createSystemEvent("PLAN_PROMPT_CREATED" /* PLAN_PROMPT_CREATED */, { prompt })
|
|
991
|
-
);
|
|
992
|
-
try {
|
|
993
|
-
const { object: uiSpec } = await ai.generateObject({
|
|
994
|
-
model: getOpenAIClient(openaiApiKey)("gpt-4o", {
|
|
995
|
-
structuredOutputs: true
|
|
996
|
-
}),
|
|
997
|
-
schema: openAIUISpec,
|
|
998
|
-
messages: [{ role: "user", content: prompt }],
|
|
999
|
-
temperature: 0.2,
|
|
1000
|
-
maxTokens: 4e3
|
|
1001
|
-
});
|
|
1002
|
-
await systemEvents.emit(
|
|
1003
|
-
createSystemEvent("PLAN_COMPLETE" /* PLAN_COMPLETE */, {
|
|
1004
|
-
layout: uiSpec,
|
|
1005
|
-
executionTimeMs: Date.now() - startTime
|
|
1006
|
-
})
|
|
1007
|
-
);
|
|
1008
|
-
return uiSpec;
|
|
1009
|
-
} catch (error) {
|
|
1010
|
-
console.error("Error calling LLM planner:", error);
|
|
1011
|
-
await systemEvents.emit(
|
|
1012
|
-
createSystemEvent("PLAN_ERROR" /* PLAN_ERROR */, {
|
|
1013
|
-
error: error instanceof Error ? error : new Error(String(error))
|
|
1014
|
-
})
|
|
1015
|
-
);
|
|
1016
|
-
throw error;
|
|
1017
|
-
}
|
|
1018
|
-
}
|
|
1019
|
-
async function processEvent(event, router, schema, layout, dataContext, goal, userContext, openaiApiKey) {
|
|
1020
|
-
const routeResolution = await router.resolveRoute(
|
|
1021
|
-
event,
|
|
1022
|
-
schema,
|
|
1023
|
-
layout || null,
|
|
1024
|
-
dataContext,
|
|
1025
|
-
goal,
|
|
1026
|
-
userContext
|
|
1027
|
-
);
|
|
1028
|
-
if (!routeResolution) {
|
|
1029
|
-
throw new Error(
|
|
1030
|
-
`No route found for event type: ${event.type}, node: ${event.nodeId}`
|
|
1031
|
-
);
|
|
1032
|
-
}
|
|
1033
|
-
if (routeResolution.actionType.toString() === "NoOp") {
|
|
1034
|
-
if (!layout)
|
|
1035
|
-
throw new Error("Layout is undefined and action is NoOp");
|
|
1036
|
-
return layout;
|
|
1037
|
-
}
|
|
1038
|
-
const plannerInputForLLM = routeResolution.plannerInput;
|
|
1039
|
-
const newLayout = await callPlannerLLM(
|
|
1040
|
-
plannerInputForLLM,
|
|
1041
|
-
openaiApiKey || "",
|
|
1042
|
-
routeResolution
|
|
1043
|
-
);
|
|
1044
|
-
return newLayout;
|
|
1045
|
-
}
|
|
1046
563
|
|
|
1047
564
|
// src/core/state.ts
|
|
565
|
+
var useChat = (config) => ({
|
|
566
|
+
append: async (message) => {
|
|
567
|
+
},
|
|
568
|
+
data: { content: "{}" },
|
|
569
|
+
isLoading: false,
|
|
570
|
+
error: null,
|
|
571
|
+
stop: () => {
|
|
572
|
+
}
|
|
573
|
+
});
|
|
1048
574
|
function useUIStateEngine({
|
|
1049
575
|
schema,
|
|
1050
576
|
goal,
|
|
1051
|
-
openaiApiKey,
|
|
1052
577
|
userContext,
|
|
1053
578
|
mockMode = false,
|
|
1054
|
-
planningConfig,
|
|
579
|
+
planningConfig = {},
|
|
1055
580
|
router = createDefaultRouter(),
|
|
1056
581
|
dataContext = {},
|
|
1057
582
|
enablePartialUpdates = false
|
|
1058
583
|
}) {
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
);
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
const route = router.resolveRoute(
|
|
1075
|
-
event,
|
|
1076
|
-
schema,
|
|
1077
|
-
state.layout,
|
|
1078
|
-
dataContext,
|
|
1079
|
-
goal,
|
|
1080
|
-
userContext
|
|
1081
|
-
);
|
|
1082
|
-
if (route) {
|
|
1083
|
-
console.log("Resolved route:", route);
|
|
1084
|
-
actionTypeForDispatch = route.actionType;
|
|
1085
|
-
targetNodeIdForDispatch = route.targetNodeId;
|
|
1086
|
-
systemEvents.emit(
|
|
1087
|
-
createSystemEvent("PLAN_START" /* PLAN_START */, {
|
|
1088
|
-
plannerInput: route.plannerInput
|
|
1089
|
-
})
|
|
1090
|
-
);
|
|
1091
|
-
if (mockMode) {
|
|
1092
|
-
resolvedNode = mockPlanner(
|
|
1093
|
-
route.plannerInput,
|
|
1094
|
-
route.targetNodeId,
|
|
1095
|
-
route.prompt
|
|
1096
|
-
);
|
|
1097
|
-
} else {
|
|
1098
|
-
resolvedNode = await callPlannerLLM(
|
|
1099
|
-
route.plannerInput,
|
|
1100
|
-
openaiApiKey || "",
|
|
1101
|
-
route
|
|
1102
|
-
);
|
|
1103
|
-
}
|
|
1104
|
-
} else {
|
|
1105
|
-
const input = {
|
|
1106
|
-
schema,
|
|
1107
|
-
goal,
|
|
1108
|
-
history: [...state.history, event],
|
|
1109
|
-
userContext
|
|
1110
|
-
};
|
|
1111
|
-
if (mockMode) {
|
|
1112
|
-
resolvedNode = mockPlanner(input);
|
|
1113
|
-
} else {
|
|
1114
|
-
resolvedNode = await callPlannerLLM(
|
|
1115
|
-
input,
|
|
1116
|
-
openaiApiKey || "",
|
|
1117
|
-
void 0
|
|
1118
|
-
);
|
|
1119
|
-
}
|
|
1120
|
-
}
|
|
1121
|
-
} else {
|
|
1122
|
-
const input = {
|
|
1123
|
-
schema,
|
|
1124
|
-
goal,
|
|
1125
|
-
history: [...state.history, event],
|
|
1126
|
-
// event is already in history from UI_EVENT dispatch
|
|
1127
|
-
userContext
|
|
1128
|
-
};
|
|
1129
|
-
if (mockMode) {
|
|
1130
|
-
resolvedNode = mockPlanner(input);
|
|
1131
|
-
} else {
|
|
1132
|
-
resolvedNode = await callPlannerLLM(
|
|
1133
|
-
input,
|
|
1134
|
-
openaiApiKey || "",
|
|
1135
|
-
void 0
|
|
1136
|
-
);
|
|
1137
|
-
}
|
|
1138
|
-
}
|
|
1139
|
-
switch (actionTypeForDispatch) {
|
|
1140
|
-
case "UPDATE_NODE" /* UPDATE_NODE */:
|
|
1141
|
-
case "SHOW_DETAIL" /* SHOW_DETAIL */:
|
|
1142
|
-
case "HIDE_DETAIL" /* HIDE_DETAIL */:
|
|
1143
|
-
case "TOGGLE_STATE" /* TOGGLE_STATE */:
|
|
1144
|
-
case "ADD_DROPDOWN" /* ADD_DROPDOWN */:
|
|
1145
|
-
case "UPDATE_FORM" /* UPDATE_FORM */:
|
|
1146
|
-
case "NAVIGATE" /* NAVIGATE */:
|
|
1147
|
-
dispatch({
|
|
1148
|
-
type: "PARTIAL_UPDATE",
|
|
1149
|
-
nodeId: targetNodeIdForDispatch,
|
|
1150
|
-
node: resolvedNode
|
|
1151
|
-
});
|
|
1152
|
-
break;
|
|
1153
|
-
case "FULL_REFRESH" /* FULL_REFRESH */:
|
|
1154
|
-
default:
|
|
1155
|
-
dispatch({ type: "AI_RESPONSE", node: resolvedNode });
|
|
1156
|
-
break;
|
|
1157
|
-
}
|
|
1158
|
-
} catch (e) {
|
|
1159
|
-
const errorMessage = e instanceof Error ? e.message : String(e);
|
|
1160
|
-
dispatch({ type: "ERROR", message: errorMessage });
|
|
584
|
+
const [state, dispatch] = react.useReducer(uiReducer, initialState);
|
|
585
|
+
const { append, data, isLoading, error, stop } = useChat();
|
|
586
|
+
const handleEvent = react.useCallback((event) => {
|
|
587
|
+
dispatch({ type: "UI_EVENT", event });
|
|
588
|
+
if (enablePartialUpdates) {
|
|
589
|
+
const route = router.resolveRoute(
|
|
590
|
+
event,
|
|
591
|
+
schema,
|
|
592
|
+
state.layout,
|
|
593
|
+
dataContext,
|
|
594
|
+
goal,
|
|
595
|
+
userContext
|
|
596
|
+
);
|
|
597
|
+
if (route) {
|
|
598
|
+
console.log("Resolved route:", route);
|
|
1161
599
|
systemEvents.emit(
|
|
1162
|
-
createSystemEvent("
|
|
1163
|
-
|
|
600
|
+
createSystemEvent("PLAN_START" /* PLAN_START */, {
|
|
601
|
+
plannerInput: route.plannerInput
|
|
1164
602
|
})
|
|
1165
603
|
);
|
|
1166
|
-
} finally {
|
|
1167
|
-
dispatch({ type: "LOADING", isLoading: false });
|
|
1168
|
-
}
|
|
1169
|
-
},
|
|
1170
|
-
[
|
|
1171
|
-
// append, // REMOVE
|
|
1172
|
-
goal,
|
|
1173
|
-
schema,
|
|
1174
|
-
state.history,
|
|
1175
|
-
// Keep state.history if input preparation needs it
|
|
1176
|
-
state.layout,
|
|
1177
|
-
// stop, // REMOVE
|
|
1178
|
-
userContext,
|
|
1179
|
-
router,
|
|
1180
|
-
mockMode,
|
|
1181
|
-
dataContext,
|
|
1182
|
-
openaiApiKey,
|
|
1183
|
-
enablePartialUpdates,
|
|
1184
|
-
dispatch
|
|
1185
|
-
// Add dispatch
|
|
1186
|
-
]
|
|
1187
|
-
);
|
|
1188
|
-
React.useEffect(() => {
|
|
1189
|
-
const initialFetch = async () => {
|
|
1190
|
-
dispatch({ type: "LOADING", isLoading: true });
|
|
1191
|
-
try {
|
|
1192
|
-
const input = {
|
|
1193
|
-
schema,
|
|
1194
|
-
goal,
|
|
1195
|
-
history: [],
|
|
1196
|
-
// Initial history is empty
|
|
1197
|
-
userContext
|
|
1198
|
-
};
|
|
1199
|
-
let node;
|
|
1200
604
|
if (mockMode) {
|
|
1201
|
-
node = mockPlanner(
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
);
|
|
1220
|
-
if (!route || !route.prompt) {
|
|
1221
|
-
console.error(
|
|
1222
|
-
"[UIStateEngine] Initial fetch: Failed to resolve route or get prompt for INIT event."
|
|
1223
|
-
);
|
|
1224
|
-
throw new Error("Failed to initialize UI due to routing error.");
|
|
605
|
+
const node = mockPlanner(route.plannerInput, route.targetNodeId, route.prompt);
|
|
606
|
+
switch (route.actionType) {
|
|
607
|
+
case "FULL_REFRESH" /* FULL_REFRESH */:
|
|
608
|
+
dispatch({ type: "AI_RESPONSE", node });
|
|
609
|
+
break;
|
|
610
|
+
case "UPDATE_NODE" /* UPDATE_NODE */:
|
|
611
|
+
case "SHOW_DETAIL" /* SHOW_DETAIL */:
|
|
612
|
+
case "HIDE_DETAIL" /* HIDE_DETAIL */:
|
|
613
|
+
case "TOGGLE_STATE" /* TOGGLE_STATE */:
|
|
614
|
+
case "ADD_DROPDOWN" /* ADD_DROPDOWN */:
|
|
615
|
+
case "UPDATE_FORM" /* UPDATE_FORM */:
|
|
616
|
+
case "NAVIGATE" /* NAVIGATE */:
|
|
617
|
+
dispatch({
|
|
618
|
+
type: "PARTIAL_UPDATE",
|
|
619
|
+
nodeId: route.targetNodeId,
|
|
620
|
+
node
|
|
621
|
+
});
|
|
622
|
+
break;
|
|
1225
623
|
}
|
|
624
|
+
} else {
|
|
625
|
+
const prompt = route.prompt;
|
|
1226
626
|
systemEvents.emit(
|
|
1227
|
-
createSystemEvent("
|
|
1228
|
-
plannerInput: route.plannerInput
|
|
1229
|
-
})
|
|
1230
|
-
);
|
|
1231
|
-
node = await callPlannerLLM(
|
|
1232
|
-
route.plannerInput,
|
|
1233
|
-
// Use plannerInput from the resolved route
|
|
1234
|
-
openaiApiKey || "",
|
|
1235
|
-
route
|
|
1236
|
-
// Pass the entire route object
|
|
627
|
+
createSystemEvent("PLAN_PROMPT_CREATED" /* PLAN_PROMPT_CREATED */, { prompt })
|
|
1237
628
|
);
|
|
629
|
+
append({
|
|
630
|
+
content: prompt,
|
|
631
|
+
role: "user"
|
|
632
|
+
});
|
|
633
|
+
sessionStorage.setItem("currentRoute", JSON.stringify({
|
|
634
|
+
actionType: route.actionType,
|
|
635
|
+
targetNodeId: route.targetNodeId
|
|
636
|
+
}));
|
|
1238
637
|
}
|
|
1239
|
-
|
|
1240
|
-
}
|
|
1241
|
-
|
|
1242
|
-
|
|
638
|
+
return;
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
const input = {
|
|
642
|
+
schema,
|
|
643
|
+
goal,
|
|
644
|
+
history: [...state.history, event],
|
|
645
|
+
userContext
|
|
646
|
+
};
|
|
647
|
+
if (mockMode) {
|
|
648
|
+
const node = mockPlanner();
|
|
649
|
+
dispatch({ type: "AI_RESPONSE", node });
|
|
650
|
+
} else {
|
|
651
|
+
const prompt = buildPrompt(input);
|
|
652
|
+
append({
|
|
653
|
+
content: prompt,
|
|
654
|
+
role: "user"
|
|
655
|
+
});
|
|
656
|
+
}
|
|
657
|
+
}, [append, goal, schema, state.history, state.layout, stop, userContext, router, mockMode, dataContext, enablePartialUpdates]);
|
|
658
|
+
react.useEffect(() => {
|
|
659
|
+
{
|
|
660
|
+
try {
|
|
1243
661
|
systemEvents.emit(
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
662
|
+
createSystemEvent("PLAN_RESPONSE_CHUNK" /* PLAN_RESPONSE_CHUNK */, {
|
|
663
|
+
chunk: data.content,
|
|
664
|
+
isComplete: true
|
|
1247
665
|
})
|
|
1248
666
|
);
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
}
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
})
|
|
1281
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1282
|
-
DialogPrimitive__namespace.Overlay,
|
|
1283
|
-
{
|
|
1284
|
-
"data-slot": "dialog-overlay",
|
|
1285
|
-
className: cn(
|
|
1286
|
-
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50",
|
|
1287
|
-
className
|
|
1288
|
-
),
|
|
1289
|
-
...props
|
|
1290
|
-
}
|
|
1291
|
-
);
|
|
1292
|
-
}
|
|
1293
|
-
function DialogContent({
|
|
1294
|
-
className,
|
|
1295
|
-
children,
|
|
1296
|
-
...props
|
|
1297
|
-
}) {
|
|
1298
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(DialogPortal, { "data-slot": "dialog-portal", children: [
|
|
1299
|
-
/* @__PURE__ */ jsxRuntime.jsx(DialogOverlay, {}),
|
|
1300
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1301
|
-
DialogPrimitive__namespace.Content,
|
|
1302
|
-
{
|
|
1303
|
-
"data-slot": "dialog-content",
|
|
1304
|
-
className: cn(
|
|
1305
|
-
"bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 sm:max-w-lg",
|
|
1306
|
-
className
|
|
1307
|
-
),
|
|
1308
|
-
...props,
|
|
1309
|
-
children: [
|
|
1310
|
-
children,
|
|
1311
|
-
/* @__PURE__ */ jsxRuntime.jsxs(DialogPrimitive__namespace.Close, { className: "ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", children: [
|
|
1312
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.XIcon, {}),
|
|
1313
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Close" })
|
|
1314
|
-
] })
|
|
1315
|
-
]
|
|
1316
|
-
}
|
|
1317
|
-
)
|
|
1318
|
-
] });
|
|
1319
|
-
}
|
|
1320
|
-
function DialogHeader({ className, ...props }) {
|
|
1321
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1322
|
-
"div",
|
|
1323
|
-
{
|
|
1324
|
-
"data-slot": "dialog-header",
|
|
1325
|
-
className: cn("flex flex-col gap-2 text-center sm:text-left", className),
|
|
1326
|
-
...props
|
|
1327
|
-
}
|
|
1328
|
-
);
|
|
1329
|
-
}
|
|
1330
|
-
function DialogTitle({
|
|
1331
|
-
className,
|
|
1332
|
-
...props
|
|
1333
|
-
}) {
|
|
1334
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1335
|
-
DialogPrimitive__namespace.Title,
|
|
1336
|
-
{
|
|
1337
|
-
"data-slot": "dialog-title",
|
|
1338
|
-
className: cn("text-lg leading-none font-semibold", className),
|
|
1339
|
-
...props
|
|
1340
|
-
}
|
|
1341
|
-
);
|
|
1342
|
-
}
|
|
1343
|
-
function DialogDescription({
|
|
1344
|
-
className,
|
|
1345
|
-
...props
|
|
1346
|
-
}) {
|
|
1347
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1348
|
-
DialogPrimitive__namespace.Description,
|
|
1349
|
-
{
|
|
1350
|
-
"data-slot": "dialog-description",
|
|
1351
|
-
className: cn("text-muted-foreground text-sm", className),
|
|
1352
|
-
...props
|
|
1353
|
-
}
|
|
1354
|
-
);
|
|
1355
|
-
}
|
|
1356
|
-
|
|
1357
|
-
// components/ui/card.tsx
|
|
1358
|
-
init_utils();
|
|
1359
|
-
function Card({ className, ...props }) {
|
|
1360
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1361
|
-
"div",
|
|
1362
|
-
{
|
|
1363
|
-
"data-slot": "card",
|
|
1364
|
-
className: cn(
|
|
1365
|
-
"bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm",
|
|
1366
|
-
className
|
|
1367
|
-
),
|
|
1368
|
-
...props
|
|
1369
|
-
}
|
|
1370
|
-
);
|
|
1371
|
-
}
|
|
1372
|
-
function CardContent({ className, ...props }) {
|
|
1373
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1374
|
-
"div",
|
|
1375
|
-
{
|
|
1376
|
-
"data-slot": "card-content",
|
|
1377
|
-
className: cn("px-6", className),
|
|
1378
|
-
...props
|
|
1379
|
-
}
|
|
1380
|
-
);
|
|
1381
|
-
}
|
|
1382
|
-
|
|
1383
|
-
// components/ui/input.tsx
|
|
1384
|
-
init_utils();
|
|
1385
|
-
function Input({ className, type, ...props }) {
|
|
1386
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1387
|
-
"input",
|
|
1388
|
-
{
|
|
1389
|
-
type,
|
|
1390
|
-
"data-slot": "input",
|
|
1391
|
-
className: cn(
|
|
1392
|
-
"file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground dark:bg-input/30 border-input flex h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
|
|
1393
|
-
"focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]",
|
|
1394
|
-
"aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
|
|
1395
|
-
className
|
|
1396
|
-
),
|
|
1397
|
-
...props
|
|
1398
|
-
}
|
|
1399
|
-
);
|
|
1400
|
-
}
|
|
1401
|
-
|
|
1402
|
-
// components/ui/textarea.tsx
|
|
1403
|
-
init_utils();
|
|
1404
|
-
function Textarea({ className, ...props }) {
|
|
1405
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1406
|
-
"textarea",
|
|
1407
|
-
{
|
|
1408
|
-
"data-slot": "textarea",
|
|
1409
|
-
className: cn(
|
|
1410
|
-
"border-input placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 flex field-sizing-content min-h-16 w-full rounded-md border bg-transparent px-3 py-2 text-base shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
|
|
1411
|
-
className
|
|
1412
|
-
),
|
|
1413
|
-
...props
|
|
1414
|
-
}
|
|
1415
|
-
);
|
|
1416
|
-
}
|
|
1417
|
-
|
|
1418
|
-
// components/ui/select.tsx
|
|
1419
|
-
init_utils();
|
|
1420
|
-
function Select({
|
|
1421
|
-
...props
|
|
1422
|
-
}) {
|
|
1423
|
-
return /* @__PURE__ */ jsxRuntime.jsx(SelectPrimitive__namespace.Root, { "data-slot": "select", ...props });
|
|
1424
|
-
}
|
|
1425
|
-
function SelectValue({
|
|
1426
|
-
...props
|
|
1427
|
-
}) {
|
|
1428
|
-
return /* @__PURE__ */ jsxRuntime.jsx(SelectPrimitive__namespace.Value, { "data-slot": "select-value", ...props });
|
|
1429
|
-
}
|
|
1430
|
-
function SelectTrigger({
|
|
1431
|
-
className,
|
|
1432
|
-
size = "default",
|
|
1433
|
-
children,
|
|
1434
|
-
...props
|
|
1435
|
-
}) {
|
|
1436
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1437
|
-
SelectPrimitive__namespace.Trigger,
|
|
1438
|
-
{
|
|
1439
|
-
"data-slot": "select-trigger",
|
|
1440
|
-
"data-size": size,
|
|
1441
|
-
className: cn(
|
|
1442
|
-
"border-input data-[placeholder]:text-muted-foreground [&_svg:not([class*='text-'])]:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 dark:hover:bg-input/50 flex w-fit items-center justify-between gap-2 rounded-md border bg-transparent px-3 py-2 text-sm whitespace-nowrap shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-9 data-[size=sm]:h-8 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
1443
|
-
className
|
|
1444
|
-
),
|
|
1445
|
-
...props,
|
|
1446
|
-
children: [
|
|
1447
|
-
children,
|
|
1448
|
-
/* @__PURE__ */ jsxRuntime.jsx(SelectPrimitive__namespace.Icon, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDownIcon, { className: "size-4 opacity-50" }) })
|
|
1449
|
-
]
|
|
1450
|
-
}
|
|
1451
|
-
);
|
|
1452
|
-
}
|
|
1453
|
-
function SelectContent({
|
|
1454
|
-
className,
|
|
1455
|
-
children,
|
|
1456
|
-
position = "popper",
|
|
1457
|
-
...props
|
|
1458
|
-
}) {
|
|
1459
|
-
return /* @__PURE__ */ jsxRuntime.jsx(SelectPrimitive__namespace.Portal, { children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1460
|
-
SelectPrimitive__namespace.Content,
|
|
1461
|
-
{
|
|
1462
|
-
"data-slot": "select-content",
|
|
1463
|
-
className: cn(
|
|
1464
|
-
"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 relative z-50 max-h-(--radix-select-content-available-height) min-w-[8rem] origin-(--radix-select-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border shadow-md",
|
|
1465
|
-
position === "popper" && "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
|
|
1466
|
-
className
|
|
1467
|
-
),
|
|
1468
|
-
position,
|
|
1469
|
-
...props,
|
|
1470
|
-
children: [
|
|
1471
|
-
/* @__PURE__ */ jsxRuntime.jsx(SelectScrollUpButton, {}),
|
|
1472
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1473
|
-
SelectPrimitive__namespace.Viewport,
|
|
1474
|
-
{
|
|
1475
|
-
className: cn(
|
|
1476
|
-
"p-1",
|
|
1477
|
-
position === "popper" && "h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)] scroll-my-1"
|
|
1478
|
-
),
|
|
1479
|
-
children
|
|
667
|
+
const jsonMatch = data.content.match(/```(?:json)?\s*([\s\S]*?)\s*```/) || [null, data.content];
|
|
668
|
+
const jsonStr = jsonMatch[1].trim();
|
|
669
|
+
const parsedJson = JSON.parse(jsonStr);
|
|
670
|
+
const validatedNode = uiSpecNode.parse(parsedJson);
|
|
671
|
+
const routeInfoStr = sessionStorage.getItem("currentRoute");
|
|
672
|
+
if (routeInfoStr && enablePartialUpdates) {
|
|
673
|
+
try {
|
|
674
|
+
const routeInfo = JSON.parse(routeInfoStr);
|
|
675
|
+
switch (routeInfo.actionType) {
|
|
676
|
+
case "FULL_REFRESH" /* FULL_REFRESH */:
|
|
677
|
+
dispatch({ type: "AI_RESPONSE", node: validatedNode });
|
|
678
|
+
break;
|
|
679
|
+
case "UPDATE_NODE" /* UPDATE_NODE */:
|
|
680
|
+
case "SHOW_DETAIL" /* SHOW_DETAIL */:
|
|
681
|
+
case "HIDE_DETAIL" /* HIDE_DETAIL */:
|
|
682
|
+
case "TOGGLE_STATE" /* TOGGLE_STATE */:
|
|
683
|
+
case "ADD_DROPDOWN" /* ADD_DROPDOWN */:
|
|
684
|
+
case "UPDATE_FORM" /* UPDATE_FORM */:
|
|
685
|
+
case "NAVIGATE" /* NAVIGATE */:
|
|
686
|
+
dispatch({
|
|
687
|
+
type: "PARTIAL_UPDATE",
|
|
688
|
+
nodeId: routeInfo.targetNodeId,
|
|
689
|
+
node: validatedNode
|
|
690
|
+
});
|
|
691
|
+
break;
|
|
692
|
+
default:
|
|
693
|
+
dispatch({ type: "AI_RESPONSE", node: validatedNode });
|
|
694
|
+
}
|
|
695
|
+
sessionStorage.removeItem("currentRoute");
|
|
696
|
+
} catch (e) {
|
|
697
|
+
console.error("Error parsing route info:", e);
|
|
698
|
+
dispatch({ type: "AI_RESPONSE", node: validatedNode });
|
|
1480
699
|
}
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
]
|
|
1484
|
-
}
|
|
1485
|
-
) });
|
|
1486
|
-
}
|
|
1487
|
-
function SelectItem({
|
|
1488
|
-
className,
|
|
1489
|
-
children,
|
|
1490
|
-
...props
|
|
1491
|
-
}) {
|
|
1492
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1493
|
-
SelectPrimitive__namespace.Item,
|
|
1494
|
-
{
|
|
1495
|
-
"data-slot": "select-item",
|
|
1496
|
-
className: cn(
|
|
1497
|
-
"focus:bg-accent focus:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex w-full cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2",
|
|
1498
|
-
className
|
|
1499
|
-
),
|
|
1500
|
-
...props,
|
|
1501
|
-
children: [
|
|
1502
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute right-2 flex size-3.5 items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(SelectPrimitive__namespace.ItemIndicator, { children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CheckIcon, { className: "size-4" }) }) }),
|
|
1503
|
-
/* @__PURE__ */ jsxRuntime.jsx(SelectPrimitive__namespace.ItemText, { children })
|
|
1504
|
-
]
|
|
1505
|
-
}
|
|
1506
|
-
);
|
|
1507
|
-
}
|
|
1508
|
-
function SelectScrollUpButton({
|
|
1509
|
-
className,
|
|
1510
|
-
...props
|
|
1511
|
-
}) {
|
|
1512
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1513
|
-
SelectPrimitive__namespace.ScrollUpButton,
|
|
1514
|
-
{
|
|
1515
|
-
"data-slot": "select-scroll-up-button",
|
|
1516
|
-
className: cn(
|
|
1517
|
-
"flex cursor-default items-center justify-center py-1",
|
|
1518
|
-
className
|
|
1519
|
-
),
|
|
1520
|
-
...props,
|
|
1521
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronUpIcon, { className: "size-4" })
|
|
1522
|
-
}
|
|
1523
|
-
);
|
|
1524
|
-
}
|
|
1525
|
-
function SelectScrollDownButton({
|
|
1526
|
-
className,
|
|
1527
|
-
...props
|
|
1528
|
-
}) {
|
|
1529
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1530
|
-
SelectPrimitive__namespace.ScrollDownButton,
|
|
1531
|
-
{
|
|
1532
|
-
"data-slot": "select-scroll-down-button",
|
|
1533
|
-
className: cn(
|
|
1534
|
-
"flex cursor-default items-center justify-center py-1",
|
|
1535
|
-
className
|
|
1536
|
-
),
|
|
1537
|
-
...props,
|
|
1538
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDownIcon, { className: "size-4" })
|
|
1539
|
-
}
|
|
1540
|
-
);
|
|
1541
|
-
}
|
|
1542
|
-
|
|
1543
|
-
// components/ui/checkbox.tsx
|
|
1544
|
-
init_utils();
|
|
1545
|
-
function Checkbox({
|
|
1546
|
-
className,
|
|
1547
|
-
...props
|
|
1548
|
-
}) {
|
|
1549
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1550
|
-
CheckboxPrimitive__namespace.Root,
|
|
1551
|
-
{
|
|
1552
|
-
"data-slot": "checkbox",
|
|
1553
|
-
className: cn(
|
|
1554
|
-
"peer border-input dark:bg-input/30 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground dark:data-[state=checked]:bg-primary data-[state=checked]:border-primary focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive size-4 shrink-0 rounded-[4px] border shadow-xs transition-shadow outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50",
|
|
1555
|
-
className
|
|
1556
|
-
),
|
|
1557
|
-
...props,
|
|
1558
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1559
|
-
CheckboxPrimitive__namespace.Indicator,
|
|
1560
|
-
{
|
|
1561
|
-
"data-slot": "checkbox-indicator",
|
|
1562
|
-
className: "flex items-center justify-center text-current transition-none",
|
|
1563
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CheckIcon, { className: "size-3.5" })
|
|
1564
|
-
}
|
|
1565
|
-
)
|
|
1566
|
-
}
|
|
1567
|
-
);
|
|
1568
|
-
}
|
|
1569
|
-
|
|
1570
|
-
// components/ui/radio-group.tsx
|
|
1571
|
-
init_utils();
|
|
1572
|
-
function RadioGroup({
|
|
1573
|
-
className,
|
|
1574
|
-
...props
|
|
1575
|
-
}) {
|
|
1576
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1577
|
-
RadioGroupPrimitive__namespace.Root,
|
|
1578
|
-
{
|
|
1579
|
-
"data-slot": "radio-group",
|
|
1580
|
-
className: cn("grid gap-3", className),
|
|
1581
|
-
...props
|
|
1582
|
-
}
|
|
1583
|
-
);
|
|
1584
|
-
}
|
|
1585
|
-
function RadioGroupItem({
|
|
1586
|
-
className,
|
|
1587
|
-
...props
|
|
1588
|
-
}) {
|
|
1589
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1590
|
-
RadioGroupPrimitive__namespace.Item,
|
|
1591
|
-
{
|
|
1592
|
-
"data-slot": "radio-group-item",
|
|
1593
|
-
className: cn(
|
|
1594
|
-
"border-input text-primary focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 aspect-square size-4 shrink-0 rounded-full border shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50",
|
|
1595
|
-
className
|
|
1596
|
-
),
|
|
1597
|
-
...props,
|
|
1598
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1599
|
-
RadioGroupPrimitive__namespace.Indicator,
|
|
1600
|
-
{
|
|
1601
|
-
"data-slot": "radio-group-indicator",
|
|
1602
|
-
className: "relative flex items-center justify-center",
|
|
1603
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CircleIcon, { className: "fill-primary absolute top-1/2 left-1/2 size-2 -translate-x-1/2 -translate-y-1/2" })
|
|
700
|
+
} else {
|
|
701
|
+
dispatch({ type: "AI_RESPONSE", node: validatedNode });
|
|
1604
702
|
}
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
}
|
|
1625
|
-
function TabsList({
|
|
1626
|
-
className,
|
|
1627
|
-
...props
|
|
1628
|
-
}) {
|
|
1629
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1630
|
-
TabsPrimitive__namespace.List,
|
|
1631
|
-
{
|
|
1632
|
-
"data-slot": "tabs-list",
|
|
1633
|
-
className: cn(
|
|
1634
|
-
"bg-muted text-muted-foreground inline-flex h-9 w-fit items-center justify-center rounded-lg p-[3px]",
|
|
1635
|
-
className
|
|
1636
|
-
),
|
|
1637
|
-
...props
|
|
1638
|
-
}
|
|
1639
|
-
);
|
|
1640
|
-
}
|
|
1641
|
-
function TabsTrigger({
|
|
1642
|
-
className,
|
|
1643
|
-
...props
|
|
1644
|
-
}) {
|
|
1645
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1646
|
-
TabsPrimitive__namespace.Trigger,
|
|
1647
|
-
{
|
|
1648
|
-
"data-slot": "tabs-trigger",
|
|
1649
|
-
className: cn(
|
|
1650
|
-
"data-[state=active]:bg-background dark:data-[state=active]:text-foreground focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:outline-ring dark:data-[state=active]:border-input dark:data-[state=active]:bg-input/30 text-foreground dark:text-muted-foreground inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-2 py-1 text-sm font-medium whitespace-nowrap transition-[color,box-shadow] focus-visible:ring-[3px] focus-visible:outline-1 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:shadow-sm [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
1651
|
-
className
|
|
1652
|
-
),
|
|
1653
|
-
...props
|
|
1654
|
-
}
|
|
1655
|
-
);
|
|
1656
|
-
}
|
|
1657
|
-
function TabsContent({
|
|
1658
|
-
className,
|
|
1659
|
-
...props
|
|
1660
|
-
}) {
|
|
1661
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1662
|
-
TabsPrimitive__namespace.Content,
|
|
1663
|
-
{
|
|
1664
|
-
"data-slot": "tabs-content",
|
|
1665
|
-
className: cn("flex-1 outline-none", className),
|
|
1666
|
-
...props
|
|
703
|
+
systemEvents.emit(
|
|
704
|
+
createSystemEvent("PLAN_COMPLETE" /* PLAN_COMPLETE */, {
|
|
705
|
+
layout: validatedNode,
|
|
706
|
+
executionTimeMs: 0
|
|
707
|
+
// Not available here
|
|
708
|
+
})
|
|
709
|
+
);
|
|
710
|
+
} catch (parseError) {
|
|
711
|
+
console.error("Failed to parse LLM response:", parseError);
|
|
712
|
+
dispatch({
|
|
713
|
+
type: "ERROR",
|
|
714
|
+
message: "Failed to parse LLM response"
|
|
715
|
+
});
|
|
716
|
+
systemEvents.emit(
|
|
717
|
+
createSystemEvent("PLAN_ERROR" /* PLAN_ERROR */, {
|
|
718
|
+
error: parseError instanceof Error ? parseError : new Error("Parse error")
|
|
719
|
+
})
|
|
720
|
+
);
|
|
721
|
+
}
|
|
1667
722
|
}
|
|
1668
|
-
);
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
{
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
)
|
|
1685
|
-
...props
|
|
723
|
+
}, [data.content, error, isLoading, enablePartialUpdates]);
|
|
724
|
+
react.useEffect(() => {
|
|
725
|
+
const input = {
|
|
726
|
+
schema,
|
|
727
|
+
goal,
|
|
728
|
+
history: [],
|
|
729
|
+
userContext
|
|
730
|
+
};
|
|
731
|
+
if (mockMode) {
|
|
732
|
+
const node = mockPlanner();
|
|
733
|
+
dispatch({ type: "AI_RESPONSE", node });
|
|
734
|
+
} else {
|
|
735
|
+
const prompt = buildPrompt(input);
|
|
736
|
+
append({
|
|
737
|
+
content: prompt,
|
|
738
|
+
role: "user"
|
|
739
|
+
});
|
|
1686
740
|
}
|
|
1687
|
-
);
|
|
741
|
+
}, [append, goal, schema, userContext, mockMode]);
|
|
742
|
+
return {
|
|
743
|
+
state,
|
|
744
|
+
dispatch,
|
|
745
|
+
handleEvent
|
|
746
|
+
};
|
|
1688
747
|
}
|
|
1689
|
-
var parseStyleString = (styleString) => {
|
|
1690
|
-
if (typeof styleString !== "string") {
|
|
1691
|
-
return typeof styleString === "object" ? styleString : {};
|
|
1692
|
-
}
|
|
1693
|
-
const style = {};
|
|
1694
|
-
styleString.split(";").forEach((declaration) => {
|
|
1695
|
-
const [property, value] = declaration.split(":");
|
|
1696
|
-
if (property && value) {
|
|
1697
|
-
const camelCasedProperty = property.trim().replace(/-([a-z])/g, (g) => g[1].toUpperCase());
|
|
1698
|
-
style[camelCasedProperty] = value.trim();
|
|
1699
|
-
}
|
|
1700
|
-
});
|
|
1701
|
-
return style;
|
|
1702
|
-
};
|
|
1703
|
-
var isArrayOf = (guard) => (arr) => Array.isArray(arr) && arr.every(guard);
|
|
1704
748
|
var ShimmerBlock = () => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full h-8 bg-gray-200 animate-pulse rounded" });
|
|
1705
749
|
var ShimmerTable = ({ rows = 3 }) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-full space-y-2", children: [
|
|
1706
750
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full h-10 bg-gray-200 animate-pulse rounded" }),
|
|
@@ -1714,696 +758,117 @@ var ShimmerCard = () => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-f
|
|
|
1714
758
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-5/6 h-4 bg-gray-200 animate-pulse rounded" })
|
|
1715
759
|
] })
|
|
1716
760
|
] });
|
|
1717
|
-
var Container = (props) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: `
|
|
1718
|
-
var Header = ({
|
|
1719
|
-
title,
|
|
1720
|
-
className
|
|
1721
|
-
}) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1722
|
-
"header",
|
|
1723
|
-
{
|
|
1724
|
-
className: `py-4 px-6 border-b border-gray-300 mb-4 bg-gray-50 dark:bg-gray-800 ${className || ""}`,
|
|
1725
|
-
children: /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-xl font-semibold text-gray-800 dark:text-white", children: title })
|
|
1726
|
-
}
|
|
1727
|
-
);
|
|
761
|
+
var Container = (props) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: `w-full ${props.className || ""}`, style: props.style, children: props.children });
|
|
762
|
+
var Header = ({ title }) => /* @__PURE__ */ jsxRuntime.jsx("header", { className: "py-4 px-6 border-b mb-4", children: /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-xl font-semibold", children: title }) });
|
|
1728
763
|
var Button = ({ onClick, children, variant = "default" }) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1729
764
|
"button",
|
|
1730
765
|
{
|
|
1731
|
-
className: `px-4 py-2 rounded
|
|
1732
|
-
onClick
|
|
766
|
+
className: `px-4 py-2 rounded font-medium ${variant === "default" ? "bg-blue-600 text-white" : variant === "outline" ? "border border-gray-300 text-gray-700" : "bg-red-600 text-white"}`,
|
|
767
|
+
onClick,
|
|
1733
768
|
children
|
|
1734
769
|
}
|
|
1735
770
|
);
|
|
771
|
+
var Table = ({ items = [], fields = [], onSelect, selectable }) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full border rounded-lg overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "w-full", children: [
|
|
772
|
+
/* @__PURE__ */ jsxRuntime.jsx("thead", { className: "bg-gray-50", children: /* @__PURE__ */ jsxRuntime.jsx("tr", { children: fields.map((field) => /* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider", children: field.label }, field.key)) }) }),
|
|
773
|
+
/* @__PURE__ */ jsxRuntime.jsx("tbody", { className: "bg-white divide-y divide-gray-200", children: items.map((item, index) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
774
|
+
"tr",
|
|
775
|
+
{
|
|
776
|
+
onClick: () => selectable && onSelect && onSelect(item),
|
|
777
|
+
className: selectable ? "cursor-pointer hover:bg-gray-50" : "",
|
|
778
|
+
children: fields.map((field) => /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-6 py-4 whitespace-nowrap text-sm text-gray-500", children: item[field.key] }, field.key))
|
|
779
|
+
},
|
|
780
|
+
index
|
|
781
|
+
)) })
|
|
782
|
+
] }) });
|
|
1736
783
|
var Detail = ({ data, fields = [], title, visible = true, onBack }) => {
|
|
1737
|
-
if (!visible)
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
title && /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-lg font-medium text-gray-800 dark:text-white", children: title }),
|
|
784
|
+
if (!visible) return null;
|
|
785
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-full border rounded-lg p-6 space-y-4", children: [
|
|
786
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-between items-center", children: [
|
|
787
|
+
title && /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-lg font-medium", children: title }),
|
|
1742
788
|
onBack && /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "outline", onClick: onBack, children: "Back" })
|
|
1743
789
|
] }),
|
|
1744
790
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-4", children: fields.map((field) => {
|
|
1745
791
|
if (field.type === "heading") {
|
|
1746
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1747
|
-
"h3",
|
|
1748
|
-
{
|
|
1749
|
-
className: "text-xl font-semibold text-gray-800 dark:text-white",
|
|
1750
|
-
children: data?.[field.key] ?? ""
|
|
1751
|
-
},
|
|
1752
|
-
field.key
|
|
1753
|
-
);
|
|
792
|
+
return /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-xl font-semibold", children: data?.[field.key] }, field.key);
|
|
1754
793
|
}
|
|
1755
794
|
if (field.type === "content") {
|
|
1756
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1757
|
-
"div",
|
|
1758
|
-
{
|
|
1759
|
-
className: "text-sm text-gray-700 dark:text-gray-300",
|
|
1760
|
-
children: data?.[field.key] ?? ""
|
|
1761
|
-
},
|
|
1762
|
-
field.key
|
|
1763
|
-
);
|
|
795
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm text-gray-700", children: data?.[field.key] }, field.key);
|
|
1764
796
|
}
|
|
1765
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1766
|
-
"
|
|
1767
|
-
{
|
|
1768
|
-
|
|
1769
|
-
children: [
|
|
1770
|
-
field.label && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-gray-600 dark:text-gray-400 font-medium", children: field.label }),
|
|
1771
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-gray-800 dark:text-gray-200", children: data?.[field.key] ?? "" })
|
|
1772
|
-
]
|
|
1773
|
-
},
|
|
1774
|
-
field.key
|
|
1775
|
-
);
|
|
797
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
|
|
798
|
+
field.label && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-gray-500", children: field.label }),
|
|
799
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm", children: data?.[field.key] })
|
|
800
|
+
] }, field.key);
|
|
1776
801
|
}) })
|
|
1777
802
|
] });
|
|
1778
803
|
};
|
|
1779
|
-
var
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
};
|
|
1788
|
-
var isObject = (value) => typeof value === "object" && value !== null;
|
|
1789
|
-
var isString = (value) => typeof value === "string";
|
|
1790
|
-
var isBoolean = (value) => typeof value === "boolean";
|
|
1791
|
-
var isButtonVariant = (value) => isString(value) && ["default", "outline", "destructive"].includes(value);
|
|
1792
|
-
var getSafeBinding = (bindings, key, validator, defaultValue) => {
|
|
1793
|
-
if (bindings && typeof bindings === "object" && key in bindings) {
|
|
1794
|
-
const value = bindings[key];
|
|
1795
|
-
if (validator(value)) {
|
|
1796
|
-
return value;
|
|
1797
|
-
}
|
|
1798
|
-
}
|
|
1799
|
-
return defaultValue;
|
|
1800
|
-
};
|
|
1801
|
-
var isReactNode = (value) => {
|
|
1802
|
-
return typeof value === "string" || typeof value === "number" || typeof value === "boolean" || value === null || typeof value === "undefined" || typeof value === "object" && value !== null && "$$typeof" in value;
|
|
1803
|
-
};
|
|
1804
|
-
var isRecordWithReactNodeValues = (value) => isObject(value) && Object.values(value).every(isReactNode);
|
|
1805
|
-
var isSelectOptionObject = (item) => isObject(item) && isString(item.value) && isString(item.label);
|
|
1806
|
-
var isTabObject = (item) => (
|
|
1807
|
-
// Allow content to be optional initially
|
|
1808
|
-
isObject(item) && isString(item.value) && isString(item.label) && (item.content === void 0 || isUISpecNode(item.content))
|
|
1809
|
-
);
|
|
1810
|
-
var isUISpecNode = (value) => {
|
|
1811
|
-
if (!isObject(value))
|
|
1812
|
-
return false;
|
|
1813
|
-
return isString(value.id) && isString(value.node_type);
|
|
1814
|
-
};
|
|
1815
|
-
var isDetailFieldObject = (item) => isObject(item) && isString(item.key) && isString(item.label) && (item.type === void 0 || isString(item.type));
|
|
1816
|
-
var createEventHandler = (node, eventName, uiEventType2, processEvent2) => {
|
|
1817
|
-
const eventConfig = node.events?.[uiEventType2];
|
|
1818
|
-
if (!processEvent2 || !eventConfig)
|
|
1819
|
-
return void 0;
|
|
1820
|
-
return (eventPayload) => {
|
|
1821
|
-
const fullEvent = {
|
|
1822
|
-
type: uiEventType2,
|
|
1823
|
-
nodeId: node.id,
|
|
1824
|
-
timestamp: Date.now(),
|
|
1825
|
-
payload: {
|
|
1826
|
-
...eventConfig.payload || {},
|
|
1827
|
-
...eventPayload || {}
|
|
1828
|
-
}
|
|
1829
|
-
};
|
|
1830
|
-
processEvent2(fullEvent);
|
|
804
|
+
var createEventHandler = (node, eventName) => {
|
|
805
|
+
const eventConfig = node.events?.[eventName];
|
|
806
|
+
if (!eventConfig) return void 0;
|
|
807
|
+
return () => {
|
|
808
|
+
console.log(`Event triggered: ${eventName} on node ${node.id}`, {
|
|
809
|
+
action: eventConfig.action,
|
|
810
|
+
target: eventConfig.target,
|
|
811
|
+
payload: eventConfig.payload
|
|
812
|
+
});
|
|
1831
813
|
};
|
|
1832
814
|
};
|
|
1833
815
|
var adapterMap = {
|
|
1834
|
-
Container: (node,
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
// Use React.cloneElement to add the key prop to the element returned by renderNode
|
|
1839
|
-
React__default.default.cloneElement(renderNode(child, processEvent2), { key: child.id })
|
|
1840
|
-
)
|
|
1841
|
-
);
|
|
1842
|
-
const style = typeof styleProp === "string" ? parseStyleString(styleProp) : styleProp;
|
|
1843
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1844
|
-
"div",
|
|
1845
|
-
{
|
|
1846
|
-
className: cn("autoui-container", className),
|
|
1847
|
-
style,
|
|
1848
|
-
...restProps,
|
|
1849
|
-
"data-id": node.id,
|
|
1850
|
-
children: [
|
|
1851
|
-
(() => {
|
|
1852
|
-
console.log(
|
|
1853
|
-
`[Adapter Debug] Rendering Container: id=${node.id}, props=`,
|
|
1854
|
-
node.props
|
|
1855
|
-
);
|
|
1856
|
-
return null;
|
|
1857
|
-
})(),
|
|
1858
|
-
children
|
|
1859
|
-
]
|
|
1860
|
-
},
|
|
1861
|
-
key
|
|
1862
|
-
);
|
|
1863
|
-
},
|
|
1864
|
-
Header: (node) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1865
|
-
Header,
|
|
816
|
+
Container: (node) => /* @__PURE__ */ jsxRuntime.jsx(Container, { style: node.props?.style, className: node.props?.className, children: node.children?.map((child) => renderNode(child)) }),
|
|
817
|
+
Header: (node) => /* @__PURE__ */ jsxRuntime.jsx(Header, { title: node.props?.title || "Untitled" }),
|
|
818
|
+
Button: (node) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
819
|
+
Button,
|
|
1866
820
|
{
|
|
1867
|
-
|
|
1868
|
-
|
|
821
|
+
variant: node.props?.variant,
|
|
822
|
+
onClick: createEventHandler(node, "onClick"),
|
|
823
|
+
children: node.props?.label || "Button"
|
|
1869
824
|
}
|
|
1870
825
|
),
|
|
1871
|
-
|
|
1872
|
-
|
|
826
|
+
ListView: (node) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
827
|
+
Table,
|
|
1873
828
|
{
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
829
|
+
items: node.bindings?.items || [],
|
|
830
|
+
fields: node.bindings?.fields || [],
|
|
831
|
+
selectable: node.props?.selectable,
|
|
832
|
+
onSelect: createEventHandler(node, "onSelect")
|
|
1877
833
|
}
|
|
1878
834
|
),
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
node.props
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
(child) => React__default.default.cloneElement(renderNode(child, processEvent2), { key: child.id })
|
|
1888
|
-
);
|
|
1889
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1890
|
-
"div",
|
|
1891
|
-
{
|
|
1892
|
-
className: cn(
|
|
1893
|
-
"autoui-listview-container space-y-2",
|
|
1894
|
-
className
|
|
1895
|
-
),
|
|
1896
|
-
style,
|
|
1897
|
-
...restProps,
|
|
1898
|
-
"data-id": node.id,
|
|
1899
|
-
children
|
|
1900
|
-
},
|
|
1901
|
-
key
|
|
1902
|
-
);
|
|
1903
|
-
},
|
|
1904
|
-
Detail: (node, processEvent2) => {
|
|
1905
|
-
const data = getSafeBinding(
|
|
1906
|
-
node.bindings,
|
|
1907
|
-
"data",
|
|
1908
|
-
isRecordWithReactNodeValues,
|
|
1909
|
-
{}
|
|
1910
|
-
);
|
|
1911
|
-
const fields = getSafeBinding(
|
|
1912
|
-
node.bindings,
|
|
1913
|
-
"fields",
|
|
1914
|
-
isArrayOf(isDetailFieldObject),
|
|
1915
|
-
[]
|
|
1916
|
-
);
|
|
1917
|
-
const title = getSafeProp(node.props, "title", isString, "");
|
|
1918
|
-
const visible = getSafeProp(node.props, "visible", isBoolean, true);
|
|
1919
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1920
|
-
Detail,
|
|
1921
|
-
{
|
|
1922
|
-
data,
|
|
1923
|
-
fields,
|
|
1924
|
-
title,
|
|
1925
|
-
visible,
|
|
1926
|
-
onBack: createEventHandler(node, "onBack", "CLICK", processEvent2)
|
|
1927
|
-
}
|
|
1928
|
-
);
|
|
1929
|
-
},
|
|
1930
|
-
Card: (node, processEvent2) => {
|
|
1931
|
-
const { className, style: styleProp, key, ...restProps } = node.props || {};
|
|
1932
|
-
const children = node.children?.map(
|
|
1933
|
-
(child) => React__default.default.cloneElement(renderNode(child, processEvent2), { key: child.id })
|
|
1934
|
-
);
|
|
1935
|
-
const style = typeof styleProp === "string" ? parseStyleString(styleProp) : styleProp;
|
|
1936
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1937
|
-
Card,
|
|
1938
|
-
{
|
|
1939
|
-
className: cn("autoui-card", className),
|
|
1940
|
-
style,
|
|
1941
|
-
...restProps,
|
|
1942
|
-
"data-id": node.id,
|
|
1943
|
-
children: /* @__PURE__ */ jsxRuntime.jsxs(CardContent, { className: "p-0", children: [
|
|
1944
|
-
" ",
|
|
1945
|
-
children
|
|
1946
|
-
] })
|
|
1947
|
-
},
|
|
1948
|
-
key
|
|
1949
|
-
);
|
|
1950
|
-
},
|
|
1951
|
-
Input: (node, processEvent2) => {
|
|
1952
|
-
const name = getSafeProp(node.props, "name", isString, "inputName");
|
|
1953
|
-
const label = getSafeProp(node.props, "label", isString, "");
|
|
1954
|
-
const value = getSafeBinding(node.bindings, "value", isString, "");
|
|
1955
|
-
const placeholder = getSafeProp(node.props, "placeholder", isString, "");
|
|
1956
|
-
const disabled = getSafeProp(node.props, "disabled", isBoolean, false);
|
|
1957
|
-
const className = getSafeProp(node.props, "className", isString, "");
|
|
1958
|
-
const handleChange = (e) => {
|
|
1959
|
-
const handler = createEventHandler(
|
|
1960
|
-
node,
|
|
1961
|
-
"onChange",
|
|
1962
|
-
"CHANGE",
|
|
1963
|
-
processEvent2
|
|
1964
|
-
);
|
|
1965
|
-
if (handler)
|
|
1966
|
-
handler({ value: e.target.value });
|
|
1967
|
-
};
|
|
1968
|
-
const handleFocus = () => {
|
|
1969
|
-
const handler = createEventHandler(
|
|
1970
|
-
node,
|
|
1971
|
-
"onFocus",
|
|
1972
|
-
"FOCUS",
|
|
1973
|
-
processEvent2
|
|
1974
|
-
);
|
|
1975
|
-
if (handler)
|
|
1976
|
-
handler({});
|
|
1977
|
-
};
|
|
1978
|
-
const handleBlur = () => {
|
|
1979
|
-
const handler = createEventHandler(node, "onBlur", "BLUR", processEvent2);
|
|
1980
|
-
if (handler)
|
|
1981
|
-
handler({});
|
|
1982
|
-
};
|
|
1983
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid w-full max-w-sm items-center gap-1.5", children: [
|
|
1984
|
-
label && /* @__PURE__ */ jsxRuntime.jsx(Label2, { htmlFor: name, children: label }),
|
|
1985
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1986
|
-
Input,
|
|
1987
|
-
{
|
|
1988
|
-
id: name,
|
|
1989
|
-
name,
|
|
1990
|
-
placeholder,
|
|
1991
|
-
disabled,
|
|
1992
|
-
value,
|
|
1993
|
-
onChange: handleChange,
|
|
1994
|
-
onFocus: handleFocus,
|
|
1995
|
-
onBlur: handleBlur,
|
|
1996
|
-
className
|
|
1997
|
-
}
|
|
1998
|
-
)
|
|
1999
|
-
] });
|
|
2000
|
-
},
|
|
2001
|
-
Select: (node, processEvent2) => {
|
|
2002
|
-
const name = getSafeProp(node.props, "name", isString, "selectName");
|
|
2003
|
-
const label = getSafeProp(node.props, "label", isString, "");
|
|
2004
|
-
const placeholder = getSafeProp(
|
|
2005
|
-
node.props,
|
|
2006
|
-
"placeholder",
|
|
2007
|
-
isString,
|
|
2008
|
-
"Select..."
|
|
2009
|
-
);
|
|
2010
|
-
const disabled = getSafeProp(node.props, "disabled", isBoolean, false);
|
|
2011
|
-
const value = getSafeBinding(node.bindings, "value", isString, "");
|
|
2012
|
-
const options = getSafeBinding(
|
|
2013
|
-
node.bindings,
|
|
2014
|
-
"options",
|
|
2015
|
-
isArrayOf(isSelectOptionObject),
|
|
2016
|
-
[]
|
|
2017
|
-
);
|
|
2018
|
-
const className = getSafeProp(node.props, "className", isString, "");
|
|
2019
|
-
const handleValueChange = (selectedValue) => {
|
|
2020
|
-
const handler = createEventHandler(
|
|
2021
|
-
node,
|
|
2022
|
-
"onValueChange",
|
|
2023
|
-
"CHANGE",
|
|
2024
|
-
processEvent2
|
|
2025
|
-
);
|
|
2026
|
-
if (handler)
|
|
2027
|
-
handler({ value: selectedValue });
|
|
2028
|
-
};
|
|
2029
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2030
|
-
"div",
|
|
2031
|
-
{
|
|
2032
|
-
className: cn("grid w-full max-w-sm items-center gap-1.5", className),
|
|
2033
|
-
children: [
|
|
2034
|
-
label && /* @__PURE__ */ jsxRuntime.jsx(Label2, { htmlFor: name, children: label }),
|
|
2035
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2036
|
-
Select,
|
|
2037
|
-
{
|
|
2038
|
-
name,
|
|
2039
|
-
value,
|
|
2040
|
-
onValueChange: handleValueChange,
|
|
2041
|
-
disabled,
|
|
2042
|
-
children: [
|
|
2043
|
-
/* @__PURE__ */ jsxRuntime.jsx(SelectTrigger, { id: name, children: /* @__PURE__ */ jsxRuntime.jsx(SelectValue, { placeholder }) }),
|
|
2044
|
-
/* @__PURE__ */ jsxRuntime.jsx(SelectContent, { children: options.map((option) => /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: option.value, children: option.label }, option.value)) })
|
|
2045
|
-
]
|
|
2046
|
-
}
|
|
2047
|
-
)
|
|
2048
|
-
]
|
|
2049
|
-
}
|
|
2050
|
-
);
|
|
2051
|
-
},
|
|
2052
|
-
Textarea: (node, processEvent2) => {
|
|
2053
|
-
const { key, ...propsWithoutKey } = node.props || {};
|
|
2054
|
-
const name = getSafeProp(propsWithoutKey, "name", isString, "textareaName");
|
|
2055
|
-
const label = getSafeProp(propsWithoutKey, "label", isString, "");
|
|
2056
|
-
const placeholder = getSafeProp(
|
|
2057
|
-
propsWithoutKey,
|
|
2058
|
-
"placeholder",
|
|
2059
|
-
isString,
|
|
2060
|
-
""
|
|
2061
|
-
);
|
|
2062
|
-
const disabled = getSafeProp(propsWithoutKey, "disabled", isBoolean, false);
|
|
2063
|
-
const rows = getSafeProp(
|
|
2064
|
-
propsWithoutKey,
|
|
2065
|
-
"rows",
|
|
2066
|
-
(v) => typeof v === "number",
|
|
2067
|
-
3
|
|
2068
|
-
);
|
|
2069
|
-
const value = getSafeBinding(node.bindings, "value", isString, "");
|
|
2070
|
-
const className = getSafeProp(propsWithoutKey, "className", isString, "");
|
|
2071
|
-
const handleChange = (e) => {
|
|
2072
|
-
const handler = createEventHandler(
|
|
2073
|
-
node,
|
|
2074
|
-
"onChange",
|
|
2075
|
-
"CHANGE",
|
|
2076
|
-
processEvent2
|
|
2077
|
-
);
|
|
2078
|
-
if (handler)
|
|
2079
|
-
handler({ value: e.target.value });
|
|
2080
|
-
};
|
|
2081
|
-
const handleFocus = () => {
|
|
2082
|
-
const handler = createEventHandler(
|
|
2083
|
-
node,
|
|
2084
|
-
"onFocus",
|
|
2085
|
-
"FOCUS",
|
|
2086
|
-
processEvent2
|
|
2087
|
-
);
|
|
2088
|
-
if (handler)
|
|
2089
|
-
handler({});
|
|
2090
|
-
};
|
|
2091
|
-
const handleBlur = () => {
|
|
2092
|
-
const handler = createEventHandler(node, "onBlur", "BLUR", processEvent2);
|
|
2093
|
-
if (handler)
|
|
2094
|
-
handler({});
|
|
2095
|
-
};
|
|
2096
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid w-full gap-1.5", children: [
|
|
2097
|
-
label && /* @__PURE__ */ jsxRuntime.jsx(Label2, { htmlFor: name, children: label }),
|
|
2098
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2099
|
-
Textarea,
|
|
2100
|
-
{
|
|
2101
|
-
id: name,
|
|
2102
|
-
name,
|
|
2103
|
-
placeholder,
|
|
2104
|
-
disabled,
|
|
2105
|
-
rows,
|
|
2106
|
-
value,
|
|
2107
|
-
onChange: handleChange,
|
|
2108
|
-
onFocus: handleFocus,
|
|
2109
|
-
onBlur: handleBlur,
|
|
2110
|
-
className
|
|
2111
|
-
}
|
|
2112
|
-
)
|
|
2113
|
-
] }, key);
|
|
2114
|
-
},
|
|
2115
|
-
Checkbox: (node, processEvent2) => {
|
|
2116
|
-
const { key, ...propsWithoutKey } = node.props || {};
|
|
2117
|
-
const name = getSafeProp(propsWithoutKey, "name", isString, "checkboxName");
|
|
2118
|
-
const label = getSafeProp(propsWithoutKey, "label", isString, "");
|
|
2119
|
-
const checked = getSafeBinding(node.bindings, "checked", isBoolean, false);
|
|
2120
|
-
const disabled = getSafeProp(propsWithoutKey, "disabled", isBoolean, false);
|
|
2121
|
-
const className = getSafeProp(propsWithoutKey, "className", isString, "");
|
|
2122
|
-
const handleCheckedChange = (isChecked) => {
|
|
2123
|
-
if (typeof isChecked === "boolean") {
|
|
2124
|
-
const handler = createEventHandler(
|
|
2125
|
-
node,
|
|
2126
|
-
"onCheckedChange",
|
|
2127
|
-
"CHANGE",
|
|
2128
|
-
processEvent2
|
|
2129
|
-
);
|
|
2130
|
-
if (handler)
|
|
2131
|
-
handler({ checked: isChecked });
|
|
2132
|
-
}
|
|
2133
|
-
};
|
|
2134
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2135
|
-
"div",
|
|
2136
|
-
{
|
|
2137
|
-
className: cn("flex items-center space-x-2", className),
|
|
2138
|
-
children: [
|
|
2139
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2140
|
-
Checkbox,
|
|
2141
|
-
{
|
|
2142
|
-
id: name,
|
|
2143
|
-
name,
|
|
2144
|
-
checked,
|
|
2145
|
-
disabled,
|
|
2146
|
-
onCheckedChange: handleCheckedChange
|
|
2147
|
-
}
|
|
2148
|
-
),
|
|
2149
|
-
label && /* @__PURE__ */ jsxRuntime.jsx(Label2, { htmlFor: name, className: "cursor-pointer", children: label })
|
|
2150
|
-
]
|
|
2151
|
-
},
|
|
2152
|
-
key
|
|
2153
|
-
);
|
|
2154
|
-
},
|
|
2155
|
-
RadioGroup: (node, processEvent2) => {
|
|
2156
|
-
const { key, ...propsWithoutKey } = node.props || {};
|
|
2157
|
-
const name = getSafeProp(
|
|
2158
|
-
propsWithoutKey,
|
|
2159
|
-
"name",
|
|
2160
|
-
isString,
|
|
2161
|
-
"radioGroupName"
|
|
2162
|
-
);
|
|
2163
|
-
const label = getSafeProp(propsWithoutKey, "label", isString, "");
|
|
2164
|
-
const value = getSafeBinding(node.bindings, "value", isString, "");
|
|
2165
|
-
const options = getSafeBinding(
|
|
2166
|
-
node.bindings,
|
|
2167
|
-
"options",
|
|
2168
|
-
isArrayOf(isSelectOptionObject),
|
|
2169
|
-
[]
|
|
2170
|
-
);
|
|
2171
|
-
const disabled = getSafeProp(propsWithoutKey, "disabled", isBoolean, false);
|
|
2172
|
-
const className = getSafeProp(propsWithoutKey, "className", isString, "");
|
|
2173
|
-
const handleValueChange = (selectedValue) => {
|
|
2174
|
-
const handler = createEventHandler(
|
|
2175
|
-
node,
|
|
2176
|
-
"onValueChange",
|
|
2177
|
-
"CHANGE",
|
|
2178
|
-
processEvent2
|
|
2179
|
-
);
|
|
2180
|
-
if (handler)
|
|
2181
|
-
handler({ value: selectedValue });
|
|
2182
|
-
};
|
|
2183
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2184
|
-
"div",
|
|
2185
|
-
{
|
|
2186
|
-
className: cn("grid gap-1.5", className),
|
|
2187
|
-
children: [
|
|
2188
|
-
label && /* @__PURE__ */ jsxRuntime.jsx(Label2, { className: "mb-1", children: label }),
|
|
2189
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2190
|
-
RadioGroup,
|
|
2191
|
-
{
|
|
2192
|
-
name,
|
|
2193
|
-
value,
|
|
2194
|
-
onValueChange: handleValueChange,
|
|
2195
|
-
disabled,
|
|
2196
|
-
className: "flex flex-col space-y-1",
|
|
2197
|
-
children: options.map((option) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center space-x-2", children: [
|
|
2198
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2199
|
-
RadioGroupItem,
|
|
2200
|
-
{
|
|
2201
|
-
value: option.value,
|
|
2202
|
-
id: `${name}-${option.value}`
|
|
2203
|
-
}
|
|
2204
|
-
),
|
|
2205
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2206
|
-
Label2,
|
|
2207
|
-
{
|
|
2208
|
-
htmlFor: `${name}-${option.value}`,
|
|
2209
|
-
className: "cursor-pointer",
|
|
2210
|
-
children: option.label
|
|
2211
|
-
}
|
|
2212
|
-
)
|
|
2213
|
-
] }, option.value))
|
|
2214
|
-
}
|
|
2215
|
-
)
|
|
2216
|
-
]
|
|
2217
|
-
},
|
|
2218
|
-
key
|
|
2219
|
-
);
|
|
2220
|
-
},
|
|
2221
|
-
Tabs: (node, processEvent2) => {
|
|
2222
|
-
const { key, ...propsWithoutKey } = node.props || {};
|
|
2223
|
-
const rawTabs = getSafeBinding(
|
|
2224
|
-
node.bindings,
|
|
2225
|
-
"tabs",
|
|
2226
|
-
isArrayOf(isTabObject),
|
|
2227
|
-
[]
|
|
2228
|
-
);
|
|
2229
|
-
const defaultValue = getSafeProp(
|
|
2230
|
-
propsWithoutKey,
|
|
2231
|
-
"defaultValue",
|
|
2232
|
-
isString,
|
|
2233
|
-
rawTabs[0]?.value || ""
|
|
2234
|
-
);
|
|
2235
|
-
const className = getSafeProp(propsWithoutKey, "className", isString, "");
|
|
2236
|
-
const handleValueChange = (value) => {
|
|
2237
|
-
const handler = createEventHandler(
|
|
2238
|
-
node,
|
|
2239
|
-
"onValueChange",
|
|
2240
|
-
"CHANGE",
|
|
2241
|
-
processEvent2
|
|
2242
|
-
);
|
|
2243
|
-
if (handler)
|
|
2244
|
-
handler({ value });
|
|
2245
|
-
};
|
|
2246
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2247
|
-
Tabs,
|
|
2248
|
-
{
|
|
2249
|
-
defaultValue,
|
|
2250
|
-
onValueChange: handleValueChange,
|
|
2251
|
-
className: cn("autoui-tabs w-full", className),
|
|
2252
|
-
"data-id": node.id,
|
|
2253
|
-
children: [
|
|
2254
|
-
/* @__PURE__ */ jsxRuntime.jsx(TabsList, { children: rawTabs.map((tab) => /* @__PURE__ */ jsxRuntime.jsx(TabsTrigger, { value: tab.value, children: tab.label }, tab.value)) }),
|
|
2255
|
-
rawTabs.map((tab) => /* @__PURE__ */ jsxRuntime.jsx(TabsContent, { value: tab.value, children: tab.content ? renderNode(tab.content, processEvent2) : null }, tab.value))
|
|
2256
|
-
]
|
|
2257
|
-
},
|
|
2258
|
-
key
|
|
2259
|
-
);
|
|
2260
|
-
},
|
|
2261
|
-
Dialog: (node, processEvent2) => {
|
|
2262
|
-
const isOpen = getSafeBinding(
|
|
2263
|
-
node.bindings,
|
|
2264
|
-
"open",
|
|
2265
|
-
isBoolean,
|
|
2266
|
-
getSafeProp(node.props, "open", isBoolean, false)
|
|
2267
|
-
);
|
|
2268
|
-
const {
|
|
2269
|
-
title,
|
|
2270
|
-
description,
|
|
2271
|
-
className,
|
|
2272
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
2273
|
-
style: _styleProp,
|
|
2274
|
-
key,
|
|
2275
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
2276
|
-
open: _openProp,
|
|
2277
|
-
...restProps
|
|
2278
|
-
} = node.props || {};
|
|
2279
|
-
const children = node.children?.map(
|
|
2280
|
-
(child) => React__default.default.cloneElement(renderNode(child, processEvent2), { key: child.id })
|
|
2281
|
-
);
|
|
2282
|
-
const handleOpenChange = (open) => {
|
|
2283
|
-
if (!open) {
|
|
2284
|
-
const handler = createEventHandler(
|
|
2285
|
-
node,
|
|
2286
|
-
"onClose",
|
|
2287
|
-
// Assumed event name in UISpec
|
|
2288
|
-
"CLICK",
|
|
2289
|
-
// Use CLICK as the event type for closing dialogs
|
|
2290
|
-
processEvent2
|
|
2291
|
-
);
|
|
2292
|
-
if (handler) {
|
|
2293
|
-
handler({});
|
|
2294
|
-
}
|
|
2295
|
-
}
|
|
2296
|
-
};
|
|
2297
|
-
console.log(
|
|
2298
|
-
`[Adapter Debug] Rendering Dialog: id=${node.id}, props=`,
|
|
2299
|
-
node.props,
|
|
2300
|
-
`isOpen=${isOpen}`
|
|
2301
|
-
);
|
|
2302
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2303
|
-
Dialog,
|
|
2304
|
-
{
|
|
2305
|
-
open: isOpen,
|
|
2306
|
-
onOpenChange: handleOpenChange,
|
|
2307
|
-
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2308
|
-
DialogContent,
|
|
2309
|
-
{
|
|
2310
|
-
className: cn("autoui-dialog-content", className),
|
|
2311
|
-
...restProps,
|
|
2312
|
-
"data-id": node.id,
|
|
2313
|
-
children: [
|
|
2314
|
-
(title || description) && /* @__PURE__ */ jsxRuntime.jsxs(DialogHeader, { children: [
|
|
2315
|
-
title && /* @__PURE__ */ jsxRuntime.jsx(DialogTitle, { children: title }),
|
|
2316
|
-
description && /* @__PURE__ */ jsxRuntime.jsx(DialogDescription, { children: description })
|
|
2317
|
-
] }),
|
|
2318
|
-
children
|
|
2319
|
-
]
|
|
2320
|
-
}
|
|
2321
|
-
)
|
|
2322
|
-
},
|
|
2323
|
-
key
|
|
2324
|
-
);
|
|
2325
|
-
},
|
|
2326
|
-
Heading: (node) => {
|
|
2327
|
-
const { className, style: styleProp, key, ...restProps } = node.props || {};
|
|
2328
|
-
const text = getSafeProp(node.props, "text", isString, "Heading");
|
|
2329
|
-
let level = getSafeProp(
|
|
2330
|
-
node.props,
|
|
2331
|
-
"level",
|
|
2332
|
-
(v) => typeof v === "number" && v >= 1 && v <= 6,
|
|
2333
|
-
2
|
|
2334
|
-
);
|
|
2335
|
-
if (typeof level !== "number" || level < 1 || level > 6) {
|
|
2336
|
-
level = 2;
|
|
835
|
+
Detail: (node) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
836
|
+
Detail,
|
|
837
|
+
{
|
|
838
|
+
data: node.bindings?.data,
|
|
839
|
+
fields: node.bindings?.fields || [],
|
|
840
|
+
title: node.props?.title,
|
|
841
|
+
visible: node.props?.visible !== false,
|
|
842
|
+
onBack: createEventHandler(node, "onBack")
|
|
2337
843
|
}
|
|
2338
|
-
|
|
2339
|
-
const style = typeof styleProp === "string" ? parseStyleString(styleProp) : styleProp;
|
|
2340
|
-
const headingStyles = {
|
|
2341
|
-
1: "scroll-m-20 text-4xl font-extrabold tracking-tight lg:text-5xl",
|
|
2342
|
-
2: "scroll-m-20 border-b pb-2 text-3xl font-semibold tracking-tight first:mt-0",
|
|
2343
|
-
3: "scroll-m-20 text-2xl font-semibold tracking-tight",
|
|
2344
|
-
4: "scroll-m-20 text-xl font-semibold tracking-tight"
|
|
2345
|
-
// Add styles for h5, h6 if needed, using text-lg, text-base etc.
|
|
2346
|
-
}[level] || "text-lg font-semibold";
|
|
2347
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2348
|
-
Tag,
|
|
2349
|
-
{
|
|
2350
|
-
className: cn(headingStyles, className),
|
|
2351
|
-
style,
|
|
2352
|
-
...restProps,
|
|
2353
|
-
children: text
|
|
2354
|
-
},
|
|
2355
|
-
key
|
|
2356
|
-
);
|
|
2357
|
-
},
|
|
2358
|
-
Text: (node) => {
|
|
2359
|
-
const { className, style: styleProp, key, ...restProps } = node.props || {};
|
|
2360
|
-
const text = getSafeProp(node.props, "text", isString, "Some text");
|
|
2361
|
-
const style = typeof styleProp === "string" ? parseStyleString(styleProp) : styleProp;
|
|
2362
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2363
|
-
"p",
|
|
2364
|
-
{
|
|
2365
|
-
className: cn("leading-7", className),
|
|
2366
|
-
style,
|
|
2367
|
-
...restProps,
|
|
2368
|
-
children: text
|
|
2369
|
-
},
|
|
2370
|
-
key
|
|
2371
|
-
);
|
|
2372
|
-
}
|
|
844
|
+
)
|
|
2373
845
|
};
|
|
2374
|
-
function renderNode(node
|
|
2375
|
-
const
|
|
2376
|
-
if (
|
|
2377
|
-
return
|
|
2378
|
-
}
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
846
|
+
function renderNode(node) {
|
|
847
|
+
const Component = adapterMap[node.type];
|
|
848
|
+
if (Component) {
|
|
849
|
+
return Component(node);
|
|
850
|
+
}
|
|
851
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-2 border border-red-300 rounded", children: [
|
|
852
|
+
/* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-sm text-red-500", children: [
|
|
853
|
+
"Unsupported component: ",
|
|
854
|
+
node.type
|
|
855
|
+
] }),
|
|
856
|
+
node.children?.map((child) => renderNode(child))
|
|
857
|
+
] });
|
|
2385
858
|
}
|
|
2386
|
-
|
|
2387
|
-
var MAX_CACHE_SIZE = 10;
|
|
2388
|
-
var CACHE_TTL = 5e3;
|
|
2389
|
-
async function renderNode2(node, adapter = "shadcn", processEvent2) {
|
|
859
|
+
async function renderNode2(node, adapter = "shadcn") {
|
|
2390
860
|
const startTime = Date.now();
|
|
2391
|
-
const nodeId = node.id;
|
|
2392
|
-
const cachedItem = renderedNodesCache.get(nodeId);
|
|
2393
|
-
if (cachedItem && startTime - cachedItem.timestamp < CACHE_TTL) {
|
|
2394
|
-
return cachedItem.element;
|
|
2395
|
-
}
|
|
2396
861
|
await systemEvents.emit(
|
|
2397
862
|
createSystemEvent("RENDER_START" /* RENDER_START */, { layout: node })
|
|
2398
863
|
);
|
|
2399
864
|
let result;
|
|
2400
865
|
switch (adapter) {
|
|
2401
866
|
case "shadcn":
|
|
2402
|
-
result = renderNode(node
|
|
867
|
+
result = renderNode(node);
|
|
2403
868
|
break;
|
|
2404
869
|
default:
|
|
2405
870
|
console.warn(`Unsupported adapter: ${adapter}, falling back to shadcn`);
|
|
2406
|
-
result = renderNode(node
|
|
871
|
+
result = renderNode(node);
|
|
2407
872
|
}
|
|
2408
873
|
await systemEvents.emit(
|
|
2409
874
|
createSystemEvent("RENDER_COMPLETE" /* RENDER_COMPLETE */, {
|
|
@@ -2411,23 +876,13 @@ async function renderNode2(node, adapter = "shadcn", processEvent2) {
|
|
|
2411
876
|
renderTimeMs: Date.now() - startTime
|
|
2412
877
|
})
|
|
2413
878
|
);
|
|
2414
|
-
renderedNodesCache.set(nodeId, {
|
|
2415
|
-
element: result,
|
|
2416
|
-
timestamp: startTime
|
|
2417
|
-
});
|
|
2418
|
-
if (renderedNodesCache.size > MAX_CACHE_SIZE) {
|
|
2419
|
-
const oldestKey = [...renderedNodesCache.entries()].sort(
|
|
2420
|
-
([, a], [, b]) => a.timestamp - b.timestamp
|
|
2421
|
-
)[0][0];
|
|
2422
|
-
renderedNodesCache.delete(oldestKey);
|
|
2423
|
-
}
|
|
2424
879
|
return result;
|
|
2425
880
|
}
|
|
2426
881
|
function renderShimmer(node, adapter = "shadcn") {
|
|
2427
882
|
if (!node) {
|
|
2428
883
|
return /* @__PURE__ */ jsxRuntime.jsx(ShimmerBlock, {});
|
|
2429
884
|
}
|
|
2430
|
-
switch (node.
|
|
885
|
+
switch (node.type) {
|
|
2431
886
|
case "ListView":
|
|
2432
887
|
return /* @__PURE__ */ jsxRuntime.jsx(ShimmerTable, { rows: 3 });
|
|
2433
888
|
case "Detail":
|
|
@@ -2440,16 +895,6 @@ function renderShimmer(node, adapter = "shadcn") {
|
|
|
2440
895
|
}
|
|
2441
896
|
|
|
2442
897
|
// src/core/bindings.ts
|
|
2443
|
-
var bindingsCache = /* @__PURE__ */ new Map();
|
|
2444
|
-
var MAX_CACHE_SIZE2 = 50;
|
|
2445
|
-
var CACHE_TTL2 = 2e3;
|
|
2446
|
-
var nodeCacheTimestamps = /* @__PURE__ */ new Map();
|
|
2447
|
-
function hashDataContext(context) {
|
|
2448
|
-
return JSON.stringify(context);
|
|
2449
|
-
}
|
|
2450
|
-
function createCacheKey(nodeId, context) {
|
|
2451
|
-
return `${nodeId}:${hashDataContext(context)}`;
|
|
2452
|
-
}
|
|
2453
898
|
function getValueByPath(context, path) {
|
|
2454
899
|
const parts = path.split(".");
|
|
2455
900
|
let current = context;
|
|
@@ -2465,265 +910,68 @@ function getValueByPath(context, path) {
|
|
|
2465
910
|
return current;
|
|
2466
911
|
}
|
|
2467
912
|
function setValueByPath(context, path, value) {
|
|
2468
|
-
if (!path) {
|
|
2469
|
-
return context;
|
|
2470
|
-
}
|
|
2471
913
|
const result = { ...context };
|
|
2472
914
|
const parts = path.split(".");
|
|
2473
915
|
let current = result;
|
|
2474
916
|
for (let i = 0; i < parts.length - 1; i++) {
|
|
2475
917
|
const part = parts[i];
|
|
2476
|
-
if (
|
|
2477
|
-
|
|
2478
|
-
`setValueByPath: Cannot traverse path "${path}". Parent segment "${parts[i - 1] || "(root)"}" is not an object.`
|
|
2479
|
-
);
|
|
2480
|
-
return context;
|
|
918
|
+
if (!(part in current) || current[part] === null || current[part] === void 0) {
|
|
919
|
+
current[part] = {};
|
|
2481
920
|
}
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
currentAsObject[part] = {};
|
|
2486
|
-
} else if (typeof nextPartValue !== "object") {
|
|
2487
|
-
console.warn(
|
|
2488
|
-
`setValueByPath: Cannot create nested path "${path}". Segment "${part}" is not an object.`
|
|
2489
|
-
);
|
|
2490
|
-
return context;
|
|
2491
|
-
} else {
|
|
2492
|
-
currentAsObject[part] = { ...nextPartValue };
|
|
921
|
+
current = current[part];
|
|
922
|
+
if (typeof current !== "object") {
|
|
923
|
+
current = {};
|
|
2493
924
|
}
|
|
2494
|
-
current = currentAsObject[part];
|
|
2495
925
|
}
|
|
2496
926
|
const lastPart = parts[parts.length - 1];
|
|
2497
|
-
|
|
2498
|
-
current[lastPart] = value;
|
|
2499
|
-
} else {
|
|
2500
|
-
console.warn(
|
|
2501
|
-
`setValueByPath: Could not set value for path "${path}". Final segment parent is not an object.`
|
|
2502
|
-
);
|
|
2503
|
-
return context;
|
|
2504
|
-
}
|
|
927
|
+
current[lastPart] = value;
|
|
2505
928
|
return result;
|
|
2506
929
|
}
|
|
2507
|
-
function processBinding(binding, context
|
|
930
|
+
function processBinding(binding, context) {
|
|
2508
931
|
if (typeof binding === "string") {
|
|
2509
|
-
|
|
2510
|
-
const pathInsideExact = exactMatchArr ? exactMatchArr[1].trim() : null;
|
|
2511
|
-
if (pathInsideExact !== null && !pathInsideExact.includes("{{") && !pathInsideExact.includes("}}")) {
|
|
2512
|
-
const pathToResolve = pathInsideExact;
|
|
2513
|
-
let resolvedValue = void 0;
|
|
2514
|
-
console.log(
|
|
2515
|
-
`[processBinding Debug] Processing EXACT template: "${binding}", Path: "${pathToResolve}", Has itemData: ${!!itemData}`
|
|
2516
|
-
);
|
|
2517
|
-
if (itemData) {
|
|
2518
|
-
try {
|
|
2519
|
-
console.log(
|
|
2520
|
-
`[processBinding Debug] itemData content (EXACT):`,
|
|
2521
|
-
JSON.parse(JSON.stringify(itemData))
|
|
2522
|
-
);
|
|
2523
|
-
} catch {
|
|
2524
|
-
}
|
|
2525
|
-
}
|
|
2526
|
-
if ((pathToResolve.startsWith("item.") || pathToResolve.startsWith("row.")) && itemData) {
|
|
2527
|
-
if (pathToResolve.startsWith("item.")) {
|
|
2528
|
-
resolvedValue = getValueByPath(itemData, pathToResolve.substring(5));
|
|
2529
|
-
} else {
|
|
2530
|
-
resolvedValue = getValueByPath(itemData, pathToResolve.substring(4));
|
|
2531
|
-
}
|
|
2532
|
-
} else if (itemData && pathToResolve in itemData) {
|
|
2533
|
-
resolvedValue = getValueByPath(itemData, pathToResolve);
|
|
2534
|
-
}
|
|
2535
|
-
if (resolvedValue === void 0) {
|
|
2536
|
-
resolvedValue = getValueByPath(context, pathToResolve);
|
|
2537
|
-
}
|
|
2538
|
-
return resolvedValue;
|
|
2539
|
-
} else if (binding.includes("{{") && binding.includes("}}")) {
|
|
2540
|
-
console.log(
|
|
2541
|
-
`[processBinding Debug] Processing EMBEDDED templates: "${binding}", Has itemData: ${!!itemData}`
|
|
2542
|
-
);
|
|
2543
|
-
if (itemData) {
|
|
2544
|
-
try {
|
|
2545
|
-
console.log(
|
|
2546
|
-
`[processBinding Debug] itemData content (EMBEDDED):`,
|
|
2547
|
-
JSON.parse(JSON.stringify(itemData))
|
|
2548
|
-
);
|
|
2549
|
-
} catch {
|
|
2550
|
-
}
|
|
2551
|
-
}
|
|
2552
|
-
const resolvedString = binding.replaceAll(
|
|
2553
|
-
/{{(.*?)}}/g,
|
|
2554
|
-
// Non-greedy match inside braces
|
|
2555
|
-
(match, path) => {
|
|
2556
|
-
const trimmedPath = path.trim();
|
|
2557
|
-
let resolvedValue = void 0;
|
|
2558
|
-
if ((trimmedPath.startsWith("item.") || trimmedPath.startsWith("row.")) && itemData) {
|
|
2559
|
-
if (trimmedPath.startsWith("item.")) {
|
|
2560
|
-
resolvedValue = getValueByPath(
|
|
2561
|
-
itemData,
|
|
2562
|
-
trimmedPath.substring(5)
|
|
2563
|
-
);
|
|
2564
|
-
} else {
|
|
2565
|
-
resolvedValue = getValueByPath(
|
|
2566
|
-
itemData,
|
|
2567
|
-
trimmedPath.substring(4)
|
|
2568
|
-
);
|
|
2569
|
-
}
|
|
2570
|
-
} else if (itemData && trimmedPath in itemData) {
|
|
2571
|
-
resolvedValue = getValueByPath(itemData, trimmedPath);
|
|
2572
|
-
}
|
|
2573
|
-
if (resolvedValue === void 0) {
|
|
2574
|
-
resolvedValue = getValueByPath(context, trimmedPath);
|
|
2575
|
-
}
|
|
2576
|
-
return resolvedValue === null || resolvedValue === void 0 ? "" : String(resolvedValue);
|
|
2577
|
-
}
|
|
2578
|
-
);
|
|
2579
|
-
return resolvedString;
|
|
2580
|
-
} else {
|
|
2581
|
-
const pathToResolve = binding;
|
|
2582
|
-
let resolvedValue = void 0;
|
|
2583
|
-
console.log(
|
|
2584
|
-
`[processBinding Debug] Processing PATH string: "${pathToResolve}", Has itemData: ${!!itemData}`
|
|
2585
|
-
);
|
|
2586
|
-
if (itemData && !pathToResolve.includes(".") && pathToResolve in itemData) {
|
|
2587
|
-
resolvedValue = getValueByPath(itemData, pathToResolve);
|
|
2588
|
-
}
|
|
2589
|
-
if (resolvedValue === void 0) {
|
|
2590
|
-
resolvedValue = getValueByPath(context, pathToResolve);
|
|
2591
|
-
}
|
|
2592
|
-
return resolvedValue;
|
|
2593
|
-
}
|
|
932
|
+
return getValueByPath(context, binding);
|
|
2594
933
|
}
|
|
2595
934
|
if (Array.isArray(binding)) {
|
|
2596
|
-
return binding.map((item) => processBinding(item, context
|
|
935
|
+
return binding.map((item) => processBinding(item, context));
|
|
2597
936
|
}
|
|
2598
937
|
if (binding !== null && typeof binding === "object") {
|
|
2599
938
|
const result = {};
|
|
2600
939
|
for (const [key, value] of Object.entries(binding)) {
|
|
2601
|
-
result[key] = processBinding(value, context
|
|
940
|
+
result[key] = processBinding(value, context);
|
|
2602
941
|
}
|
|
2603
942
|
return result;
|
|
2604
943
|
}
|
|
2605
944
|
return binding;
|
|
2606
945
|
}
|
|
2607
|
-
async function resolveBindings(node, context
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
const cachedNode = bindingsCache.get(cacheKey);
|
|
2612
|
-
const cachedTimestamp = nodeCacheTimestamps.get(cacheKey);
|
|
2613
|
-
if (cachedNode && cachedTimestamp && currentTime - cachedTimestamp < CACHE_TTL2) {
|
|
2614
|
-
return cachedNode;
|
|
2615
|
-
}
|
|
2616
|
-
if (!itemData) {
|
|
2617
|
-
await systemEvents.emit(
|
|
2618
|
-
createSystemEvent("BINDING_RESOLUTION_START" /* BINDING_RESOLUTION_START */, {
|
|
2619
|
-
layout: node
|
|
2620
|
-
})
|
|
2621
|
-
);
|
|
2622
|
-
}
|
|
946
|
+
async function resolveBindings(node, context) {
|
|
947
|
+
await systemEvents.emit(
|
|
948
|
+
createSystemEvent("BINDING_RESOLUTION_START" /* BINDING_RESOLUTION_START */, { layout: node })
|
|
949
|
+
);
|
|
2623
950
|
const result = {
|
|
2624
951
|
...node,
|
|
2625
|
-
props: node.props ?
|
|
2626
|
-
events: node.events ?
|
|
2627
|
-
bindings: node.bindings ? JSON.parse(JSON.stringify(node.bindings)) : null,
|
|
2628
|
-
children: null
|
|
2629
|
-
// Initialize children to null
|
|
952
|
+
props: node.props ? { ...node.props } : void 0,
|
|
953
|
+
events: node.events ? { ...node.events } : void 0
|
|
2630
954
|
};
|
|
2631
|
-
const resolvedBindings = {};
|
|
2632
955
|
if (node.bindings) {
|
|
2633
|
-
for (const [key,
|
|
2634
|
-
const
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
if (!result.props)
|
|
956
|
+
for (const [key, binding] of Object.entries(node.bindings)) {
|
|
957
|
+
const value = processBinding(binding, context);
|
|
958
|
+
if (value !== void 0) {
|
|
959
|
+
if (!result.props) {
|
|
2638
960
|
result.props = {};
|
|
2639
|
-
result.props[key] = resolvedValue;
|
|
2640
|
-
}
|
|
2641
|
-
}
|
|
2642
|
-
}
|
|
2643
|
-
result.bindings = null;
|
|
2644
|
-
if (node.events) {
|
|
2645
|
-
result.events = processBinding(
|
|
2646
|
-
node.events,
|
|
2647
|
-
context,
|
|
2648
|
-
itemData
|
|
2649
|
-
);
|
|
2650
|
-
} else {
|
|
2651
|
-
result.events = null;
|
|
2652
|
-
}
|
|
2653
|
-
const dataBindingValue = resolvedBindings["data"] ?? resolvedBindings["items"];
|
|
2654
|
-
if ((node.node_type === "ListView" || node.node_type === "Table") && Array.isArray(dataBindingValue) && node.children && node.children.length > 0) {
|
|
2655
|
-
const templateChild = node.children[0];
|
|
2656
|
-
const mappedChildren = await Promise.all(
|
|
2657
|
-
dataBindingValue.map(async (currentItemData, index) => {
|
|
2658
|
-
try {
|
|
2659
|
-
if (typeof currentItemData !== "object" || currentItemData === null) {
|
|
2660
|
-
console.warn(
|
|
2661
|
-
`List item at index ${index} for node ${node.id} is not an object:`,
|
|
2662
|
-
currentItemData
|
|
2663
|
-
);
|
|
2664
|
-
return null;
|
|
2665
|
-
}
|
|
2666
|
-
const currentItemAsRecord = currentItemData;
|
|
2667
|
-
const itemId = currentItemAsRecord.id;
|
|
2668
|
-
const instanceId = `${templateChild.id}-${itemId || index}`;
|
|
2669
|
-
const childNodeInstance = JSON.parse(
|
|
2670
|
-
JSON.stringify(templateChild)
|
|
2671
|
-
);
|
|
2672
|
-
childNodeInstance.id = instanceId;
|
|
2673
|
-
const resolvedChild = await resolveBindings(
|
|
2674
|
-
childNodeInstance,
|
|
2675
|
-
context,
|
|
2676
|
-
currentItemAsRecord
|
|
2677
|
-
);
|
|
2678
|
-
if (!resolvedChild.props)
|
|
2679
|
-
resolvedChild.props = {};
|
|
2680
|
-
resolvedChild.props.key = itemId || `${node.id}-item-${index}`;
|
|
2681
|
-
return resolvedChild;
|
|
2682
|
-
} catch (error) {
|
|
2683
|
-
console.error(
|
|
2684
|
-
`[resolveBindings Error] Error processing item at index ${index} for node ${node.id}:`,
|
|
2685
|
-
error,
|
|
2686
|
-
"Item Data:",
|
|
2687
|
-
currentItemData
|
|
2688
|
-
);
|
|
2689
|
-
return null;
|
|
2690
961
|
}
|
|
2691
|
-
|
|
2692
|
-
);
|
|
2693
|
-
result.children = mappedChildren.filter(
|
|
2694
|
-
(child) => child !== null
|
|
2695
|
-
);
|
|
2696
|
-
} else if (node.children && node.children.length > 0) {
|
|
2697
|
-
result.children = await Promise.all(
|
|
2698
|
-
node.children.map((child) => resolveBindings(child, context, itemData))
|
|
2699
|
-
);
|
|
2700
|
-
} else {
|
|
2701
|
-
result.children = [];
|
|
2702
|
-
}
|
|
2703
|
-
if (!itemData) {
|
|
2704
|
-
await systemEvents.emit(
|
|
2705
|
-
createSystemEvent("BINDING_RESOLUTION_COMPLETE" /* BINDING_RESOLUTION_COMPLETE */, {
|
|
2706
|
-
originalLayout: node,
|
|
2707
|
-
resolvedLayout: result
|
|
2708
|
-
})
|
|
2709
|
-
);
|
|
2710
|
-
}
|
|
2711
|
-
bindingsCache.set(cacheKey, result);
|
|
2712
|
-
nodeCacheTimestamps.set(cacheKey, currentTime);
|
|
2713
|
-
if (bindingsCache.size > MAX_CACHE_SIZE2) {
|
|
2714
|
-
let oldestKey = null;
|
|
2715
|
-
let oldestTimestamp = currentTime;
|
|
2716
|
-
for (const [key, timestamp] of nodeCacheTimestamps.entries()) {
|
|
2717
|
-
if (timestamp < oldestTimestamp) {
|
|
2718
|
-
oldestTimestamp = timestamp;
|
|
2719
|
-
oldestKey = key;
|
|
962
|
+
result.props[key] = value;
|
|
2720
963
|
}
|
|
2721
964
|
}
|
|
2722
|
-
if (oldestKey) {
|
|
2723
|
-
bindingsCache.delete(oldestKey);
|
|
2724
|
-
nodeCacheTimestamps.delete(oldestKey);
|
|
2725
|
-
}
|
|
2726
965
|
}
|
|
966
|
+
if (node.children) {
|
|
967
|
+
result.children = await Promise.all(node.children.map((child) => resolveBindings(child, context)));
|
|
968
|
+
}
|
|
969
|
+
await systemEvents.emit(
|
|
970
|
+
createSystemEvent("BINDING_RESOLUTION_COMPLETE" /* BINDING_RESOLUTION_COMPLETE */, {
|
|
971
|
+
originalLayout: node,
|
|
972
|
+
resolvedLayout: result
|
|
973
|
+
})
|
|
974
|
+
);
|
|
2727
975
|
return result;
|
|
2728
976
|
}
|
|
2729
977
|
function executeAction(action, targetId, payload, context = {}, layoutTree) {
|
|
@@ -2746,6 +994,7 @@ function executeAction(action, targetId, payload, context = {}, layoutTree) {
|
|
|
2746
994
|
}
|
|
2747
995
|
break;
|
|
2748
996
|
}
|
|
997
|
+
// Add more actions as needed
|
|
2749
998
|
default:
|
|
2750
999
|
console.warn(`Unknown action: ${action}`);
|
|
2751
1000
|
}
|
|
@@ -2759,7 +1008,7 @@ var EventManager = class {
|
|
|
2759
1008
|
}
|
|
2760
1009
|
/**
|
|
2761
1010
|
* Register a hook for specific event types
|
|
2762
|
-
*
|
|
1011
|
+
*
|
|
2763
1012
|
* @param eventTypes - Event types to register for, or 'all' for all events
|
|
2764
1013
|
* @param hook - Hook function to execute
|
|
2765
1014
|
* @returns Unregister function
|
|
@@ -2792,7 +1041,7 @@ var EventManager = class {
|
|
|
2792
1041
|
}
|
|
2793
1042
|
/**
|
|
2794
1043
|
* Process an event through all registered hooks
|
|
2795
|
-
*
|
|
1044
|
+
*
|
|
2796
1045
|
* @param event - The UI event to process
|
|
2797
1046
|
* @returns Whether the default action should proceed
|
|
2798
1047
|
*/
|
|
@@ -2813,15 +1062,13 @@ var EventManager = class {
|
|
|
2813
1062
|
if (this.hooks.all) {
|
|
2814
1063
|
for (const hook of this.hooks.all) {
|
|
2815
1064
|
await hook(context);
|
|
2816
|
-
if (propagationStopped)
|
|
2817
|
-
break;
|
|
1065
|
+
if (propagationStopped) break;
|
|
2818
1066
|
}
|
|
2819
1067
|
}
|
|
2820
1068
|
if (!propagationStopped && this.hooks[event.type]) {
|
|
2821
1069
|
for (const hook of this.hooks[event.type] || []) {
|
|
2822
1070
|
await hook(context);
|
|
2823
|
-
if (propagationStopped)
|
|
2824
|
-
break;
|
|
1071
|
+
if (propagationStopped) break;
|
|
2825
1072
|
}
|
|
2826
1073
|
}
|
|
2827
1074
|
return !defaultPrevented;
|
|
@@ -2838,45 +1085,6 @@ function createEventHook(eventTypes, hook, options) {
|
|
|
2838
1085
|
}
|
|
2839
1086
|
};
|
|
2840
1087
|
}
|
|
2841
|
-
|
|
2842
|
-
// src/core/component-detection.ts
|
|
2843
|
-
function areShadcnComponentsAvailable() {
|
|
2844
|
-
try {
|
|
2845
|
-
init_button();
|
|
2846
|
-
return true;
|
|
2847
|
-
} catch (error) {
|
|
2848
|
-
return false;
|
|
2849
|
-
}
|
|
2850
|
-
}
|
|
2851
|
-
function getMissingComponentsMessage() {
|
|
2852
|
-
return `Missing required shadcn components. Please run:
|
|
2853
|
-
> npm run setup-shadcn`;
|
|
2854
|
-
}
|
|
2855
|
-
function correctListBindingsRecursive(node, dataContext) {
|
|
2856
|
-
const correctedNode = JSON.parse(JSON.stringify(node));
|
|
2857
|
-
if ((correctedNode.node_type === "ListView" || correctedNode.node_type === "Table") && correctedNode.bindings?.data) {
|
|
2858
|
-
const bindingPath = correctedNode.bindings.data;
|
|
2859
|
-
if (typeof bindingPath === "string") {
|
|
2860
|
-
const pathSegments = bindingPath.split(".");
|
|
2861
|
-
const mainKey = pathSegments[0];
|
|
2862
|
-
if (pathSegments.length === 1) {
|
|
2863
|
-
const potentialDataContextEntry = dataContext[mainKey];
|
|
2864
|
-
if (potentialDataContextEntry && typeof potentialDataContextEntry === "object" && potentialDataContextEntry !== null && "data" in potentialDataContextEntry && Array.isArray(potentialDataContextEntry.data)) {
|
|
2865
|
-
correctedNode.bindings.data = `${mainKey}.data`;
|
|
2866
|
-
console.log(
|
|
2867
|
-
`[AutoUI Debug] Corrected list binding for node '${correctedNode.id}': from '${mainKey}' to '${mainKey}.data'`
|
|
2868
|
-
);
|
|
2869
|
-
}
|
|
2870
|
-
}
|
|
2871
|
-
}
|
|
2872
|
-
}
|
|
2873
|
-
if (correctedNode.children) {
|
|
2874
|
-
correctedNode.children = correctedNode.children.map(
|
|
2875
|
-
(child) => correctListBindingsRecursive(child, dataContext)
|
|
2876
|
-
);
|
|
2877
|
-
}
|
|
2878
|
-
return correctedNode;
|
|
2879
|
-
}
|
|
2880
1088
|
var AutoUI = ({
|
|
2881
1089
|
schema,
|
|
2882
1090
|
goal,
|
|
@@ -2886,34 +1094,24 @@ var AutoUI = ({
|
|
|
2886
1094
|
eventHooks,
|
|
2887
1095
|
systemEventHooks,
|
|
2888
1096
|
debugMode = false,
|
|
2889
|
-
mockMode =
|
|
1097
|
+
mockMode = true,
|
|
1098
|
+
databaseConfig,
|
|
2890
1099
|
planningConfig,
|
|
2891
1100
|
integration = {},
|
|
2892
1101
|
scope = {},
|
|
2893
|
-
enablePartialUpdates = false
|
|
2894
|
-
openaiApiKey
|
|
1102
|
+
enablePartialUpdates = false
|
|
2895
1103
|
}) => {
|
|
2896
|
-
const [schemaAdapterInstance] =
|
|
2897
|
-
const [dataContext, setDataContext] =
|
|
2898
|
-
const [componentsAvailable, setComponentsAvailable] = React.useState(true);
|
|
1104
|
+
const [schemaAdapterInstance, setSchemaAdapterInstance] = react.useState(null);
|
|
1105
|
+
const [dataContext, setDataContext] = react.useState({});
|
|
2899
1106
|
const effectiveSchema = schema;
|
|
2900
1107
|
const scopedGoal = goal;
|
|
2901
|
-
|
|
2902
|
-
if (componentAdapter === "shadcn") {
|
|
2903
|
-
setComponentsAvailable(areShadcnComponentsAvailable());
|
|
2904
|
-
}
|
|
2905
|
-
}, [componentAdapter]);
|
|
2906
|
-
React.useEffect(() => {
|
|
1108
|
+
react.useEffect(() => {
|
|
2907
1109
|
const unregisters = [];
|
|
2908
1110
|
if (systemEventHooks) {
|
|
2909
1111
|
Object.entries(systemEventHooks).forEach(([eventType, hooks]) => {
|
|
2910
|
-
if (!hooks)
|
|
2911
|
-
return;
|
|
1112
|
+
if (!hooks) return;
|
|
2912
1113
|
hooks.forEach((hook) => {
|
|
2913
|
-
const unregister = systemEvents.on(
|
|
2914
|
-
eventType,
|
|
2915
|
-
hook
|
|
2916
|
-
);
|
|
1114
|
+
const unregister = systemEvents.on(eventType, hook);
|
|
2917
1115
|
unregisters.push(unregister);
|
|
2918
1116
|
});
|
|
2919
1117
|
});
|
|
@@ -2922,9 +1120,7 @@ var AutoUI = ({
|
|
|
2922
1120
|
const debugHook = (event) => {
|
|
2923
1121
|
console.debug(`[AutoUI Debug] System Event:`, event);
|
|
2924
1122
|
};
|
|
2925
|
-
Object.values(SystemEventType).
|
|
2926
|
-
(eventType) => eventType !== "RENDER_START" /* RENDER_START */ && eventType !== "BINDING_RESOLUTION_START" /* BINDING_RESOLUTION_START */
|
|
2927
|
-
).forEach((eventType) => {
|
|
1123
|
+
Object.values(SystemEventType).forEach((eventType) => {
|
|
2928
1124
|
const unregister = systemEvents.on(eventType, debugHook);
|
|
2929
1125
|
unregisters.push(unregister);
|
|
2930
1126
|
});
|
|
@@ -2933,7 +1129,7 @@ var AutoUI = ({
|
|
|
2933
1129
|
unregisters.forEach((unregister) => unregister());
|
|
2934
1130
|
};
|
|
2935
1131
|
}, [systemEventHooks, debugMode]);
|
|
2936
|
-
|
|
1132
|
+
react.useEffect(() => {
|
|
2937
1133
|
const initializeDataContext = async () => {
|
|
2938
1134
|
let initialData = {};
|
|
2939
1135
|
if (schemaAdapterInstance) {
|
|
@@ -2963,162 +1159,88 @@ var AutoUI = ({
|
|
|
2963
1159
|
planningConfig,
|
|
2964
1160
|
router: void 0,
|
|
2965
1161
|
dataContext,
|
|
2966
|
-
enablePartialUpdates
|
|
2967
|
-
openaiApiKey
|
|
1162
|
+
enablePartialUpdates
|
|
2968
1163
|
});
|
|
2969
|
-
const eventManagerRef =
|
|
2970
|
-
|
|
2971
|
-
if (!eventHooks)
|
|
2972
|
-
return;
|
|
1164
|
+
const eventManagerRef = react.useRef(new EventManager());
|
|
1165
|
+
react.useEffect(() => {
|
|
1166
|
+
if (!eventHooks) return;
|
|
2973
1167
|
const unregisters = [];
|
|
2974
1168
|
if (eventHooks.all) {
|
|
2975
|
-
const unregister = eventManagerRef.current.register(
|
|
2976
|
-
|
|
2977
|
-
|
|
2978
|
-
|
|
2979
|
-
await hook(ctx);
|
|
2980
|
-
if (ctx.isPropagationStopped())
|
|
2981
|
-
break;
|
|
2982
|
-
}
|
|
1169
|
+
const unregister = eventManagerRef.current.register("all", async (ctx) => {
|
|
1170
|
+
for (const hook of eventHooks.all || []) {
|
|
1171
|
+
await hook(ctx);
|
|
1172
|
+
if (ctx.isPropagationStopped()) break;
|
|
2983
1173
|
}
|
|
2984
|
-
);
|
|
1174
|
+
});
|
|
2985
1175
|
unregisters.push(unregister);
|
|
2986
1176
|
}
|
|
2987
1177
|
Object.entries(eventHooks).forEach(([type, hooks]) => {
|
|
2988
|
-
if (type === "all" || !hooks)
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
|
|
2993
|
-
for (const hook of hooks) {
|
|
2994
|
-
await hook(ctx);
|
|
2995
|
-
if (ctx.isPropagationStopped())
|
|
2996
|
-
break;
|
|
2997
|
-
}
|
|
1178
|
+
if (type === "all" || !hooks) return;
|
|
1179
|
+
const unregister = eventManagerRef.current.register([type], async (ctx) => {
|
|
1180
|
+
for (const hook of hooks) {
|
|
1181
|
+
await hook(ctx);
|
|
1182
|
+
if (ctx.isPropagationStopped()) break;
|
|
2998
1183
|
}
|
|
2999
|
-
);
|
|
1184
|
+
});
|
|
3000
1185
|
unregisters.push(unregister);
|
|
3001
1186
|
});
|
|
3002
1187
|
return () => {
|
|
3003
1188
|
unregisters.forEach((unregister) => unregister());
|
|
3004
1189
|
};
|
|
3005
1190
|
}, [eventHooks]);
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
for (const child of node.children) {
|
|
3023
|
-
const found = findNodeById2(child, id);
|
|
3024
|
-
if (found)
|
|
3025
|
-
return found;
|
|
3026
|
-
}
|
|
1191
|
+
react.useCallback(async (event) => {
|
|
1192
|
+
const shouldProceed = await eventManagerRef.current.processEvent(event);
|
|
1193
|
+
if (onEvent) {
|
|
1194
|
+
onEvent(event);
|
|
1195
|
+
}
|
|
1196
|
+
if (!shouldProceed) {
|
|
1197
|
+
console.info("Event processing was prevented by hooks", event);
|
|
1198
|
+
return;
|
|
1199
|
+
}
|
|
1200
|
+
const findNodeById2 = (node, id) => {
|
|
1201
|
+
if (!node) return void 0;
|
|
1202
|
+
if (node.id === id) return node;
|
|
1203
|
+
if (node.children) {
|
|
1204
|
+
for (const child of node.children) {
|
|
1205
|
+
const found = findNodeById2(child, id);
|
|
1206
|
+
if (found) return found;
|
|
3027
1207
|
}
|
|
3028
|
-
return void 0;
|
|
3029
|
-
};
|
|
3030
|
-
const sourceNode = findNodeById2(state.layout, event.nodeId);
|
|
3031
|
-
if (!sourceNode) {
|
|
3032
|
-
console.warn(`Node not found for event: ${event.nodeId}`);
|
|
3033
|
-
handleEvent(event);
|
|
3034
|
-
return;
|
|
3035
|
-
}
|
|
3036
|
-
const eventConfig = sourceNode.events?.[event.type];
|
|
3037
|
-
if (!eventConfig) {
|
|
3038
|
-
console.warn(
|
|
3039
|
-
`No event config found for ${event.type} on node ${event.nodeId}`
|
|
3040
|
-
);
|
|
3041
|
-
handleEvent(event);
|
|
3042
|
-
return;
|
|
3043
1208
|
}
|
|
3044
|
-
|
|
3045
|
-
|
|
3046
|
-
|
|
3047
|
-
|
|
3048
|
-
|
|
3049
|
-
...eventConfig.payload,
|
|
3050
|
-
...event.payload
|
|
3051
|
-
},
|
|
3052
|
-
dataContext,
|
|
3053
|
-
state.layout || void 0
|
|
3054
|
-
);
|
|
3055
|
-
setDataContext(newContext);
|
|
1209
|
+
return void 0;
|
|
1210
|
+
};
|
|
1211
|
+
const sourceNode = findNodeById2(state.layout, event.nodeId);
|
|
1212
|
+
if (!sourceNode) {
|
|
1213
|
+
console.warn(`Node not found for event: ${event.nodeId}`);
|
|
3056
1214
|
handleEvent(event);
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
|
|
3068
|
-
|
|
3069
|
-
|
|
3070
|
-
|
|
3071
|
-
|
|
3072
|
-
|
|
3073
|
-
|
|
3074
|
-
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
|
|
3079
|
-
|
|
3080
|
-
|
|
3081
|
-
|
|
3082
|
-
JSON.stringify(correctedLayout, null, 2)
|
|
3083
|
-
);
|
|
3084
|
-
const resolved = await resolveBindings(correctedLayout, dataContext);
|
|
3085
|
-
setResolvedLayout(resolved);
|
|
3086
|
-
console.log(
|
|
3087
|
-
"[AutoUI Debug] Resolved layout after bindings:",
|
|
3088
|
-
JSON.stringify(resolved, null, 2)
|
|
3089
|
-
);
|
|
1215
|
+
return;
|
|
1216
|
+
}
|
|
1217
|
+
const eventConfig = sourceNode.events?.[event.type];
|
|
1218
|
+
if (!eventConfig) {
|
|
1219
|
+
console.warn(`No event config found for ${event.type} on node ${event.nodeId}`);
|
|
1220
|
+
handleEvent(event);
|
|
1221
|
+
return;
|
|
1222
|
+
}
|
|
1223
|
+
const newContext = executeAction(
|
|
1224
|
+
eventConfig.action,
|
|
1225
|
+
eventConfig.target,
|
|
1226
|
+
{
|
|
1227
|
+
...eventConfig.payload,
|
|
1228
|
+
...event.payload
|
|
1229
|
+
},
|
|
1230
|
+
dataContext,
|
|
1231
|
+
state.layout
|
|
1232
|
+
);
|
|
1233
|
+
setDataContext(newContext);
|
|
1234
|
+
handleEvent(event);
|
|
1235
|
+
}, [dataContext, handleEvent, onEvent, state.layout]);
|
|
1236
|
+
const [resolvedLayout, setResolvedLayout] = react.useState(void 0);
|
|
1237
|
+
react.useEffect(() => {
|
|
1238
|
+
if (state.layout) {
|
|
1239
|
+
resolveBindings(state.layout, dataContext).then((resolved) => setResolvedLayout(resolved)).catch((err) => console.error("Error resolving bindings:", err));
|
|
3090
1240
|
} else {
|
|
3091
1241
|
setResolvedLayout(void 0);
|
|
3092
1242
|
}
|
|
3093
1243
|
}, [state.layout, dataContext]);
|
|
3094
|
-
React.useEffect(() => {
|
|
3095
|
-
resolveLayoutBindings();
|
|
3096
|
-
}, [resolveLayoutBindings]);
|
|
3097
|
-
const renderResolvedLayout = React.useCallback(async () => {
|
|
3098
|
-
if (resolvedLayout) {
|
|
3099
|
-
try {
|
|
3100
|
-
const rendered = await renderNode2(
|
|
3101
|
-
resolvedLayout,
|
|
3102
|
-
componentAdapter,
|
|
3103
|
-
processEvent2
|
|
3104
|
-
);
|
|
3105
|
-
setRenderedNode(rendered);
|
|
3106
|
-
} catch (err) {
|
|
3107
|
-
console.error("Error rendering node:", err);
|
|
3108
|
-
}
|
|
3109
|
-
} else {
|
|
3110
|
-
setRenderedNode(null);
|
|
3111
|
-
}
|
|
3112
|
-
}, [resolvedLayout, componentAdapter, processEvent2]);
|
|
3113
|
-
React.useEffect(() => {
|
|
3114
|
-
renderResolvedLayout();
|
|
3115
|
-
}, [renderResolvedLayout]);
|
|
3116
|
-
if (!componentsAvailable) {
|
|
3117
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "autoui-error p-4 border border-red-300 bg-red-50 text-red-700 rounded", children: [
|
|
3118
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-medium", children: "Component Library Not Found" }),
|
|
3119
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm whitespace-pre-line", children: getMissingComponentsMessage() })
|
|
3120
|
-
] });
|
|
3121
|
-
}
|
|
3122
1244
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3123
1245
|
"div",
|
|
3124
1246
|
{
|
|
@@ -3135,24 +1257,11 @@ var AutoUI = ({
|
|
|
3135
1257
|
] }) })
|
|
3136
1258
|
) : (
|
|
3137
1259
|
// Render the resolved layout
|
|
3138
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "autoui-content", children:
|
|
1260
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "autoui-content", children: renderNode2(resolvedLayout, componentAdapter) })
|
|
3139
1261
|
),
|
|
3140
|
-
state.error && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "autoui-error
|
|
3141
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "autoui-error-title
|
|
3142
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "autoui-error-message
|
|
3143
|
-
!mockMode && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-4 text-sm text-red-600 dark:text-red-300", children: [
|
|
3144
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { children: "This could be because:" }),
|
|
3145
|
-
/* @__PURE__ */ jsxRuntime.jsxs("ul", { className: "list-disc pl-5 mt-2", children: [
|
|
3146
|
-
/* @__PURE__ */ jsxRuntime.jsx("li", { children: "Your OpenAI API key is missing or invalid" }),
|
|
3147
|
-
/* @__PURE__ */ jsxRuntime.jsx("li", { children: "The OpenAI service is experiencing issues" }),
|
|
3148
|
-
/* @__PURE__ */ jsxRuntime.jsx("li", { children: "Your API rate limit has been exceeded" })
|
|
3149
|
-
] }),
|
|
3150
|
-
/* @__PURE__ */ jsxRuntime.jsxs("p", { className: "mt-2", children: [
|
|
3151
|
-
"Try setting ",
|
|
3152
|
-
/* @__PURE__ */ jsxRuntime.jsx("code", { children: "mockMode=true" }),
|
|
3153
|
-
" to use sample data instead."
|
|
3154
|
-
] })
|
|
3155
|
-
] })
|
|
1262
|
+
state.error && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "autoui-error", children: [
|
|
1263
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "autoui-error-title", children: "Error generating UI" }),
|
|
1264
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "autoui-error-message", children: state.error })
|
|
3156
1265
|
] })
|
|
3157
1266
|
]
|
|
3158
1267
|
}
|
|
@@ -3205,26 +1314,26 @@ var DrizzleAdapter = class {
|
|
|
3205
1314
|
*/
|
|
3206
1315
|
mapDataType(drizzleType) {
|
|
3207
1316
|
const typeMap = {
|
|
3208
|
-
serial: "integer",
|
|
3209
|
-
integer: "integer",
|
|
3210
|
-
int: "integer",
|
|
3211
|
-
bigint: "integer",
|
|
3212
|
-
text: "string",
|
|
3213
|
-
varchar: "string",
|
|
3214
|
-
char: "string",
|
|
3215
|
-
boolean: "boolean",
|
|
3216
|
-
bool: "boolean",
|
|
3217
|
-
timestamp: "datetime",
|
|
3218
|
-
timestamptz: "datetime",
|
|
3219
|
-
date: "date",
|
|
3220
|
-
time: "time",
|
|
3221
|
-
json: "object",
|
|
3222
|
-
jsonb: "object",
|
|
3223
|
-
real: "number",
|
|
3224
|
-
float: "number",
|
|
3225
|
-
double: "number",
|
|
3226
|
-
numeric: "number",
|
|
3227
|
-
decimal: "number"
|
|
1317
|
+
"serial": "integer",
|
|
1318
|
+
"integer": "integer",
|
|
1319
|
+
"int": "integer",
|
|
1320
|
+
"bigint": "integer",
|
|
1321
|
+
"text": "string",
|
|
1322
|
+
"varchar": "string",
|
|
1323
|
+
"char": "string",
|
|
1324
|
+
"boolean": "boolean",
|
|
1325
|
+
"bool": "boolean",
|
|
1326
|
+
"timestamp": "datetime",
|
|
1327
|
+
"timestamptz": "datetime",
|
|
1328
|
+
"date": "date",
|
|
1329
|
+
"time": "time",
|
|
1330
|
+
"json": "object",
|
|
1331
|
+
"jsonb": "object",
|
|
1332
|
+
"real": "number",
|
|
1333
|
+
"float": "number",
|
|
1334
|
+
"double": "number",
|
|
1335
|
+
"numeric": "number",
|
|
1336
|
+
"decimal": "number"
|
|
3228
1337
|
};
|
|
3229
1338
|
return typeMap[drizzleType.toLowerCase()] || "string";
|
|
3230
1339
|
}
|
|
@@ -3267,122 +1376,10 @@ function createSchemaAdapter(options) {
|
|
|
3267
1376
|
case "custom":
|
|
3268
1377
|
return options.adapter;
|
|
3269
1378
|
default:
|
|
3270
|
-
throw new Error(
|
|
3271
|
-
`Unsupported schema adapter type: ${options.type}`
|
|
3272
|
-
);
|
|
1379
|
+
throw new Error(`Unsupported schema adapter type: ${options.type}`);
|
|
3273
1380
|
}
|
|
3274
1381
|
}
|
|
3275
1382
|
|
|
3276
|
-
// src/ai-utils.ts
|
|
3277
|
-
var generateComponent = async (prompt) => {
|
|
3278
|
-
console.warn(
|
|
3279
|
-
"generateComponent is a placeholder and will be implemented in a future version"
|
|
3280
|
-
);
|
|
3281
|
-
return `<div>Generated Component for: ${prompt}</div>`;
|
|
3282
|
-
};
|
|
3283
|
-
var generateUIDescription = async (prompt) => {
|
|
3284
|
-
console.warn(
|
|
3285
|
-
"generateUIDescription is a placeholder and will be implemented in a future version"
|
|
3286
|
-
);
|
|
3287
|
-
return `Description for ${prompt}`;
|
|
3288
|
-
};
|
|
3289
|
-
var generateUIComponent = async (prompt) => {
|
|
3290
|
-
console.warn(
|
|
3291
|
-
"generateUIComponent is a placeholder and will be implemented in a future version"
|
|
3292
|
-
);
|
|
3293
|
-
return `<div>Generated UI Component for: ${prompt}</div>`;
|
|
3294
|
-
};
|
|
3295
|
-
function usePlanner(options) {
|
|
3296
|
-
const {
|
|
3297
|
-
schema,
|
|
3298
|
-
goal,
|
|
3299
|
-
openaiApiKey,
|
|
3300
|
-
userContext,
|
|
3301
|
-
initialLayout,
|
|
3302
|
-
mockMode: optionsMockMode
|
|
3303
|
-
} = options;
|
|
3304
|
-
const [layout, setLayout] = React.useState(
|
|
3305
|
-
initialLayout || void 0
|
|
3306
|
-
);
|
|
3307
|
-
const [loading, setLoading] = React.useState(false);
|
|
3308
|
-
const [error, setError] = React.useState(null);
|
|
3309
|
-
const router = options.router || createDefaultRouter();
|
|
3310
|
-
const dataContext = {};
|
|
3311
|
-
const initialFetchAttempted = React.useRef(false);
|
|
3312
|
-
const mockMode = optionsMockMode || !openaiApiKey;
|
|
3313
|
-
const generateInitialLayout = React.useCallback(async () => {
|
|
3314
|
-
setLoading(true);
|
|
3315
|
-
setError(null);
|
|
3316
|
-
try {
|
|
3317
|
-
const plannerInput2 = {
|
|
3318
|
-
schema,
|
|
3319
|
-
goal,
|
|
3320
|
-
userContext: userContext || null,
|
|
3321
|
-
history: null
|
|
3322
|
-
};
|
|
3323
|
-
let generatedLayout;
|
|
3324
|
-
if (mockMode) {
|
|
3325
|
-
console.warn(
|
|
3326
|
-
"Using mock planner in usePlanner hook (mockMode enabled or API key missing)."
|
|
3327
|
-
);
|
|
3328
|
-
generatedLayout = mockPlanner(plannerInput2);
|
|
3329
|
-
} else {
|
|
3330
|
-
generatedLayout = await callPlannerLLM(
|
|
3331
|
-
plannerInput2,
|
|
3332
|
-
openaiApiKey,
|
|
3333
|
-
void 0
|
|
3334
|
-
);
|
|
3335
|
-
}
|
|
3336
|
-
setLayout(generatedLayout);
|
|
3337
|
-
} catch (err) {
|
|
3338
|
-
setError(err instanceof Error ? err : new Error(String(err)));
|
|
3339
|
-
} finally {
|
|
3340
|
-
setLoading(false);
|
|
3341
|
-
}
|
|
3342
|
-
}, [schema, goal, userContext, openaiApiKey, mockMode]);
|
|
3343
|
-
const handleEvent = React.useCallback(
|
|
3344
|
-
async (event) => {
|
|
3345
|
-
if (!layout) {
|
|
3346
|
-
setError(new Error("Cannot handle event - no layout exists"));
|
|
3347
|
-
return;
|
|
3348
|
-
}
|
|
3349
|
-
setLoading(true);
|
|
3350
|
-
setError(null);
|
|
3351
|
-
try {
|
|
3352
|
-
const updatedLayout = await processEvent(
|
|
3353
|
-
event,
|
|
3354
|
-
router,
|
|
3355
|
-
schema,
|
|
3356
|
-
layout,
|
|
3357
|
-
dataContext,
|
|
3358
|
-
goal,
|
|
3359
|
-
userContext,
|
|
3360
|
-
openaiApiKey
|
|
3361
|
-
);
|
|
3362
|
-
setLayout(updatedLayout);
|
|
3363
|
-
} catch (err) {
|
|
3364
|
-
setError(err instanceof Error ? err : new Error(String(err)));
|
|
3365
|
-
} finally {
|
|
3366
|
-
setLoading(false);
|
|
3367
|
-
}
|
|
3368
|
-
},
|
|
3369
|
-
[layout, router, schema, dataContext, goal, userContext, openaiApiKey]
|
|
3370
|
-
);
|
|
3371
|
-
React.useEffect(() => {
|
|
3372
|
-
if (options.initialLayout === void 0 && layout === void 0 && !initialFetchAttempted.current) {
|
|
3373
|
-
initialFetchAttempted.current = true;
|
|
3374
|
-
generateInitialLayout();
|
|
3375
|
-
}
|
|
3376
|
-
}, [options.initialLayout, layout, generateInitialLayout]);
|
|
3377
|
-
return {
|
|
3378
|
-
layout,
|
|
3379
|
-
loading,
|
|
3380
|
-
error,
|
|
3381
|
-
handleEvent,
|
|
3382
|
-
generateInitialLayout
|
|
3383
|
-
};
|
|
3384
|
-
}
|
|
3385
|
-
|
|
3386
1383
|
exports.ActionRouter = ActionRouter;
|
|
3387
1384
|
exports.ActionType = ActionType;
|
|
3388
1385
|
exports.AutoUI = AutoUI;
|
|
@@ -3392,13 +1389,9 @@ exports.createDefaultRouter = createDefaultRouter;
|
|
|
3392
1389
|
exports.createEventHook = createEventHook;
|
|
3393
1390
|
exports.createSchemaAdapter = createSchemaAdapter;
|
|
3394
1391
|
exports.createSystemEvent = createSystemEvent;
|
|
3395
|
-
exports.generateComponent = generateComponent;
|
|
3396
|
-
exports.generateUIComponent = generateUIComponent;
|
|
3397
|
-
exports.generateUIDescription = generateUIDescription;
|
|
3398
1392
|
exports.systemEvents = systemEvents;
|
|
3399
1393
|
exports.uiEvent = uiEvent;
|
|
3400
1394
|
exports.uiEventType = uiEventType;
|
|
3401
1395
|
exports.uiSpecNode = uiSpecNode;
|
|
3402
|
-
|
|
3403
|
-
//# sourceMappingURL=out.js.map
|
|
1396
|
+
//# sourceMappingURL=index.js.map
|
|
3404
1397
|
//# sourceMappingURL=index.js.map
|