@alpaca-editor/core 1.0.4093 → 1.0.4095
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/ui/input.js +1 -1
- package/dist/components/ui/popover.d.ts +3 -1
- package/dist/components/ui/popover.js +1 -1
- package/dist/components/ui/popover.js.map +1 -1
- package/dist/components/ui/select.js +5 -3
- package/dist/components/ui/select.js.map +1 -1
- package/dist/config/config.js +1 -9
- package/dist/config/config.js.map +1 -1
- package/dist/editor/Editor.js +1 -1
- package/dist/editor/Editor.js.map +1 -1
- package/dist/editor/FieldList.js +1 -1
- package/dist/editor/FieldList.js.map +1 -1
- package/dist/editor/FieldListField.js +9 -3
- package/dist/editor/FieldListField.js.map +1 -1
- package/dist/editor/ItemInfo.js +1 -1
- package/dist/editor/ItemInfo.js.map +1 -1
- package/dist/editor/LinkEditorDialog.js +6 -6
- package/dist/editor/LinkEditorDialog.js.map +1 -1
- package/dist/editor/ai/AgentTerminal.js +32 -3
- package/dist/editor/ai/AgentTerminal.js.map +1 -1
- package/dist/editor/ai/AiResponseMessage.js +2 -2
- package/dist/editor/ai/AiResponseMessage.js.map +1 -1
- package/dist/editor/control-center/setup-steps/AiSetupStep.js +251 -7
- package/dist/editor/control-center/setup-steps/AiSetupStep.js.map +1 -1
- package/dist/editor/field-types/DateFieldEditor.js +1 -1
- package/dist/editor/field-types/DateFieldEditor.js.map +1 -1
- package/dist/editor/field-types/DateTimeFieldEditor.js +1 -1
- package/dist/editor/field-types/DateTimeFieldEditor.js.map +1 -1
- package/dist/editor/field-types/DropLinkEditor.js +1 -1
- package/dist/editor/field-types/DropLinkEditor.js.map +1 -1
- package/dist/editor/field-types/DropListEditor.js +1 -1
- package/dist/editor/field-types/DropListEditor.js.map +1 -1
- package/dist/editor/field-types/InternalLinkFieldEditor.js +1 -1
- package/dist/editor/field-types/InternalLinkFieldEditor.js.map +1 -1
- package/dist/editor/field-types/LinkFieldEditor.js +2 -1
- package/dist/editor/field-types/LinkFieldEditor.js.map +1 -1
- package/dist/editor/field-types/TreeListEditor.js +75 -70
- package/dist/editor/field-types/TreeListEditor.js.map +1 -1
- package/dist/editor/menubar/PageSelector.js +2 -1
- package/dist/editor/menubar/PageSelector.js.map +1 -1
- package/dist/editor/page-editor-chrome/FrameMenu.js +2 -2
- package/dist/editor/page-editor-chrome/InlineEditor.js +8 -0
- package/dist/editor/page-editor-chrome/InlineEditor.js.map +1 -1
- package/dist/editor/page-editor-chrome/PictureEditorOverlay.js +8 -0
- package/dist/editor/page-editor-chrome/PictureEditorOverlay.js.map +1 -1
- package/dist/editor/page-viewer/DeviceToolbar.js +2 -1
- package/dist/editor/page-viewer/DeviceToolbar.js.map +1 -1
- package/dist/editor/page-viewer/EditorForm.js +1 -5
- package/dist/editor/page-viewer/EditorForm.js.map +1 -1
- package/dist/editor/page-viewer/PageViewerFrame.js +17 -0
- package/dist/editor/page-viewer/PageViewerFrame.js.map +1 -1
- package/dist/editor/pageModel.d.ts +1 -0
- package/dist/editor/services/aiService.d.ts +1 -0
- package/dist/editor/services/aiService.js.map +1 -1
- package/dist/editor/ui/Splitter.d.ts +1 -0
- package/dist/editor/ui/Splitter.js +9 -4
- package/dist/editor/ui/Splitter.js.map +1 -1
- package/dist/page-wizard/steps/ComponentTypesSelector.js +1 -1
- package/dist/page-wizard/steps/ComponentTypesSelector.js.map +1 -1
- package/dist/page-wizard/steps/ContentStep.js +81 -69
- package/dist/page-wizard/steps/ContentStep.js.map +1 -1
- package/dist/page-wizard/utils/dataAccessor.js +11 -5
- package/dist/page-wizard/utils/dataAccessor.js.map +1 -1
- package/dist/revision.d.ts +2 -2
- package/dist/revision.js +2 -2
- package/dist/styles.css +12 -3
- package/package.json +1 -1
- package/src/components/ui/input.tsx +1 -1
- package/src/components/ui/popover.tsx +22 -15
- package/src/components/ui/select.tsx +44 -29
- package/src/config/config.tsx +0 -12
- package/src/editor/Editor.tsx +1 -1
- package/src/editor/FieldList.tsx +4 -1
- package/src/editor/FieldListField.tsx +10 -4
- package/src/editor/ItemInfo.tsx +1 -1
- package/src/editor/LinkEditorDialog.tsx +25 -19
- package/src/editor/ai/AgentTerminal.tsx +58 -28
- package/src/editor/ai/AiResponseMessage.tsx +4 -4
- package/src/editor/control-center/setup-steps/AiSetupStep.tsx +362 -40
- package/src/editor/field-types/DateFieldEditor.tsx +2 -1
- package/src/editor/field-types/DateTimeFieldEditor.tsx +1 -1
- package/src/editor/field-types/DropLinkEditor.tsx +8 -6
- package/src/editor/field-types/DropListEditor.tsx +11 -9
- package/src/editor/field-types/InternalLinkFieldEditor.tsx +1 -1
- package/src/editor/field-types/LinkFieldEditor.tsx +2 -1
- package/src/editor/field-types/TreeListEditor.tsx +178 -178
- package/src/editor/menubar/PageSelector.tsx +3 -3
- package/src/editor/page-editor-chrome/FrameMenu.tsx +1 -1
- package/src/editor/page-editor-chrome/InlineEditor.tsx +10 -0
- package/src/editor/page-editor-chrome/PictureEditorOverlay.tsx +11 -0
- package/src/editor/page-viewer/DeviceToolbar.tsx +9 -2
- package/src/editor/page-viewer/EditorForm.tsx +1 -6
- package/src/editor/page-viewer/PageViewerFrame.tsx +28 -0
- package/src/editor/pageModel.ts +1 -0
- package/src/editor/services/aiService.ts +2 -0
- package/src/editor/ui/Splitter.tsx +26 -2
- package/src/page-wizard/steps/ComponentTypesSelector.tsx +1 -1
- package/src/page-wizard/steps/ContentStep.tsx +129 -106
- package/src/page-wizard/utils/dataAccessor.ts +13 -5
- package/src/revision.ts +2 -2
|
@@ -7,7 +7,12 @@ import { useEditContext } from "../../client/editContext";
|
|
|
7
7
|
import { ItemDescriptor } from "../../pageModel";
|
|
8
8
|
import { getChildren } from "../../services/contentService";
|
|
9
9
|
import type { ItemTreeNodeData } from "../../services/contentService";
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
CheckCircle,
|
|
12
|
+
RefreshCw,
|
|
13
|
+
SparklesIcon,
|
|
14
|
+
AlertCircle,
|
|
15
|
+
} from "lucide-react";
|
|
11
16
|
import { contentItemId } from "../../../config/config";
|
|
12
17
|
|
|
13
18
|
type StepState = "idle" | "checking" | "success" | "error";
|
|
@@ -32,20 +37,36 @@ export function AiSetupStep() {
|
|
|
32
37
|
const [aiError, setAiError] = useState<string | null>(null);
|
|
33
38
|
const [apiKey, setApiKey] = useState<string>("");
|
|
34
39
|
|
|
35
|
-
const [editorSettingsItem, setEditorSettingsItem] =
|
|
40
|
+
const [editorSettingsItem, setEditorSettingsItem] =
|
|
41
|
+
useState<ItemDescriptor | null>(null);
|
|
36
42
|
const [containersError, setContainersError] = useState<string | null>(null);
|
|
37
43
|
const requiredContainers = useMemo(
|
|
38
44
|
() => [
|
|
39
45
|
{ name: "Ai Models", templateId: "e5f6a7b8-9c0d-1e2f-3a4b-5c6d7e8f9a0b" },
|
|
40
|
-
{
|
|
41
|
-
|
|
42
|
-
|
|
46
|
+
{
|
|
47
|
+
name: "Ai Endpoints",
|
|
48
|
+
templateId: "4592f2e0-06e4-470e-9820-7fd4ea148e00",
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
name: "Ai Profiles",
|
|
52
|
+
templateId: "4298ab78-2aaa-4d5f-bb3a-0bd321b86063",
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
name: "Ai Schemas",
|
|
56
|
+
templateId: "5214a52b-6c45-4671-97f2-703fe24e3d09",
|
|
57
|
+
},
|
|
43
58
|
{ name: "Ai Quotas", templateId: "7a08ff28-70ed-459b-a7f2-db2a78d88f46" },
|
|
44
|
-
{
|
|
59
|
+
{
|
|
60
|
+
name: "AI Generators",
|
|
61
|
+
templateId: "9430a3e9-7397-4598-9a55-2b263c927497",
|
|
62
|
+
},
|
|
63
|
+
{ name: "AI Tools", templateId: "7e3f9d9d-8e84-4e57-b12e-6e9c99d4fd11" },
|
|
45
64
|
],
|
|
46
65
|
[],
|
|
47
66
|
);
|
|
48
|
-
const [containerStates, setContainerStates] = useState<
|
|
67
|
+
const [containerStates, setContainerStates] = useState<
|
|
68
|
+
Record<string, StepState>
|
|
69
|
+
>({});
|
|
49
70
|
const [busyMap, setBusyMap] = useState<Record<string, boolean>>({});
|
|
50
71
|
|
|
51
72
|
const userLang = editContext?.contentEditorItem?.language || "en";
|
|
@@ -85,6 +106,270 @@ export function AiSetupStep() {
|
|
|
85
106
|
[editContext?.sessionId, userLang],
|
|
86
107
|
);
|
|
87
108
|
|
|
109
|
+
// IDs for tool templates/fields
|
|
110
|
+
const AI_TOOLS_TEMPLATE_ID = "7e3f9d9d-8e84-4e57-b12e-6e9c99d4fd11"; // container
|
|
111
|
+
const AI_TOOL_TEMPLATE_ID = "a2e8a0d9-7b1f-4d1a-a2d8-8f3ea6d6f0b1"; // item template
|
|
112
|
+
const FIELD_FUNCTION_NAME_ID = "3d9f2b1a-9d44-4d26-8a1b-92f0fb4d3a2c";
|
|
113
|
+
const FIELD_LABEL_ID = "5a19f5a5-1d21-4b6a-9f83-6f3fc0b34b2e";
|
|
114
|
+
const FIELD_DESCRIPTION_ID = "6b2e4b8e-8a9f-4d8f-9f6e-1a2b3c4d5e6f";
|
|
115
|
+
|
|
116
|
+
const [toolsBusy, setToolsBusy] = useState(false);
|
|
117
|
+
const [toolsError, setToolsError] = useState<string | null>(null);
|
|
118
|
+
|
|
119
|
+
const ensureAiToolsAndGenerate = useCallback(async () => {
|
|
120
|
+
if (!editContext) return;
|
|
121
|
+
try {
|
|
122
|
+
setToolsBusy(true);
|
|
123
|
+
setToolsError(null);
|
|
124
|
+
|
|
125
|
+
// Resolve /Settings/Editor
|
|
126
|
+
const settingsItem = await resolvePathUnderContent([
|
|
127
|
+
"Settings",
|
|
128
|
+
"Editor",
|
|
129
|
+
]);
|
|
130
|
+
if (!settingsItem)
|
|
131
|
+
throw new Error("Editor settings item not found. Create it first.");
|
|
132
|
+
|
|
133
|
+
// Ensure AI Tools container exists
|
|
134
|
+
const editorChildren = (await getChildren(
|
|
135
|
+
settingsItem.id,
|
|
136
|
+
editContext.sessionId!,
|
|
137
|
+
[],
|
|
138
|
+
false,
|
|
139
|
+
userLang,
|
|
140
|
+
"path",
|
|
141
|
+
)) as unknown as ItemTreeNodeData[];
|
|
142
|
+
|
|
143
|
+
let aiToolsParent = findByName(editorChildren, "AI Tools");
|
|
144
|
+
if (!aiToolsParent) {
|
|
145
|
+
const created = await editContext.operations.createItem(
|
|
146
|
+
settingsItem,
|
|
147
|
+
AI_TOOLS_TEMPLATE_ID,
|
|
148
|
+
"AI Tools",
|
|
149
|
+
);
|
|
150
|
+
if (!created) throw new Error("Failed to create 'AI Tools' container");
|
|
151
|
+
aiToolsParent = {
|
|
152
|
+
id: created.id,
|
|
153
|
+
name: "AI Tools",
|
|
154
|
+
displayName: "AI Tools",
|
|
155
|
+
thumbUrl: "",
|
|
156
|
+
previewUrl: "",
|
|
157
|
+
templateId: "",
|
|
158
|
+
icon: "",
|
|
159
|
+
hasChildren: false,
|
|
160
|
+
isComponent: false,
|
|
161
|
+
language: userLang,
|
|
162
|
+
version: 0,
|
|
163
|
+
hasLayout: false,
|
|
164
|
+
} as unknown as ItemTreeNodeData;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Get existing tool items under AI Tools
|
|
168
|
+
const toolChildren = (await getChildren(
|
|
169
|
+
aiToolsParent.id,
|
|
170
|
+
editContext.sessionId!,
|
|
171
|
+
[],
|
|
172
|
+
false,
|
|
173
|
+
userLang,
|
|
174
|
+
"path",
|
|
175
|
+
)) as unknown as ItemTreeNodeData[];
|
|
176
|
+
|
|
177
|
+
const findChildByLabel = (label: string) =>
|
|
178
|
+
findByName(toolChildren, label);
|
|
179
|
+
|
|
180
|
+
// Known tool functions (aligned with backend function names)
|
|
181
|
+
const tools: {
|
|
182
|
+
functionName: string;
|
|
183
|
+
label: string;
|
|
184
|
+
description?: string;
|
|
185
|
+
}[] = [
|
|
186
|
+
{
|
|
187
|
+
functionName: "get-content",
|
|
188
|
+
label: "Get Content",
|
|
189
|
+
description: "Returns page content or selected components",
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
functionName: "edit-field",
|
|
193
|
+
label: "Edit Field",
|
|
194
|
+
description: "Edits a field on the page or datasource",
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
functionName: "suggest-field-edit",
|
|
198
|
+
label: "Suggest Field Edit",
|
|
199
|
+
description: "Suggests changes to a field's content",
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
functionName: "create-item",
|
|
203
|
+
label: "Create Item",
|
|
204
|
+
description: "Creates a new item using a template",
|
|
205
|
+
},
|
|
206
|
+
{
|
|
207
|
+
functionName: "load-item",
|
|
208
|
+
label: "Load Item",
|
|
209
|
+
description: "Loads an item for context",
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
functionName: "get-items",
|
|
213
|
+
label: "Get Items",
|
|
214
|
+
description: "Finds items by criteria",
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
functionName: "get-children",
|
|
218
|
+
label: "Get Children",
|
|
219
|
+
description: "Lists child items under a parent",
|
|
220
|
+
},
|
|
221
|
+
{
|
|
222
|
+
functionName: "get-insertoptions",
|
|
223
|
+
label: "Get Insert Options",
|
|
224
|
+
description: "Lists available insert templates for an item",
|
|
225
|
+
},
|
|
226
|
+
{
|
|
227
|
+
functionName: "add-component",
|
|
228
|
+
label: "Add Component",
|
|
229
|
+
description: "Adds a component to a placeholder",
|
|
230
|
+
},
|
|
231
|
+
{
|
|
232
|
+
functionName: "remove-component",
|
|
233
|
+
label: "Remove Component",
|
|
234
|
+
description: "Removes a component from the page",
|
|
235
|
+
},
|
|
236
|
+
{
|
|
237
|
+
functionName: "move-components",
|
|
238
|
+
label: "Move Components",
|
|
239
|
+
description: "Moves components between placeholders",
|
|
240
|
+
},
|
|
241
|
+
{
|
|
242
|
+
functionName: "get-placeholders",
|
|
243
|
+
label: "Get Placeholders",
|
|
244
|
+
description: "Lists placeholders for a component",
|
|
245
|
+
},
|
|
246
|
+
{
|
|
247
|
+
functionName: "get-component-props-and-placeholders",
|
|
248
|
+
label: "Get Component Props and Placeholders",
|
|
249
|
+
description: "Returns component prop schema and placeholders",
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
functionName: "search-content",
|
|
253
|
+
label: "Search Content",
|
|
254
|
+
description: "Searches content across the index",
|
|
255
|
+
},
|
|
256
|
+
{
|
|
257
|
+
functionName: "search-images",
|
|
258
|
+
label: "Search Images",
|
|
259
|
+
description: "Searches images for use in content",
|
|
260
|
+
},
|
|
261
|
+
{
|
|
262
|
+
functionName: "google-search",
|
|
263
|
+
label: "Google Search",
|
|
264
|
+
description: "Performs a web search",
|
|
265
|
+
},
|
|
266
|
+
{
|
|
267
|
+
functionName: "scrape-webpage",
|
|
268
|
+
label: "Scrape Webpage",
|
|
269
|
+
description: "Fetches a webpage and extracts content",
|
|
270
|
+
},
|
|
271
|
+
{
|
|
272
|
+
functionName: "edit-image",
|
|
273
|
+
label: "Edit Image",
|
|
274
|
+
description: "Uses AI to modify an image",
|
|
275
|
+
},
|
|
276
|
+
{
|
|
277
|
+
functionName: "get-picture-description",
|
|
278
|
+
label: "Get Picture Description",
|
|
279
|
+
description: "Describes an image",
|
|
280
|
+
},
|
|
281
|
+
{
|
|
282
|
+
functionName: "add-comment",
|
|
283
|
+
label: "Add Comment",
|
|
284
|
+
description: "Adds a comment to the page",
|
|
285
|
+
},
|
|
286
|
+
{
|
|
287
|
+
functionName: "get-comments",
|
|
288
|
+
label: "Get Comments",
|
|
289
|
+
description: "Lists comments on the page",
|
|
290
|
+
},
|
|
291
|
+
{
|
|
292
|
+
functionName: "get-suggestions",
|
|
293
|
+
label: "Get Suggestions",
|
|
294
|
+
description: "Provides AI suggestions",
|
|
295
|
+
},
|
|
296
|
+
];
|
|
297
|
+
|
|
298
|
+
// Create or update tool items
|
|
299
|
+
for (const t of tools) {
|
|
300
|
+
let node = findChildByLabel(t.label);
|
|
301
|
+
if (!node) {
|
|
302
|
+
const created = await editContext.operations.createItem(
|
|
303
|
+
{
|
|
304
|
+
id: aiToolsParent.id,
|
|
305
|
+
language: userLang,
|
|
306
|
+
version: 0,
|
|
307
|
+
} as ItemDescriptor,
|
|
308
|
+
AI_TOOL_TEMPLATE_ID,
|
|
309
|
+
t.label,
|
|
310
|
+
);
|
|
311
|
+
if (!created) throw new Error(`Failed to create tool '${t.label}'`);
|
|
312
|
+
node = {
|
|
313
|
+
id: created.id,
|
|
314
|
+
name: t.label,
|
|
315
|
+
displayName: t.label,
|
|
316
|
+
thumbUrl: "",
|
|
317
|
+
previewUrl: "",
|
|
318
|
+
templateId: "",
|
|
319
|
+
icon: "",
|
|
320
|
+
hasChildren: false,
|
|
321
|
+
isComponent: false,
|
|
322
|
+
language: userLang,
|
|
323
|
+
version: 0,
|
|
324
|
+
hasLayout: false,
|
|
325
|
+
} as unknown as ItemTreeNodeData;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// Set Function Name
|
|
329
|
+
await editContext.operations.editField({
|
|
330
|
+
field: {
|
|
331
|
+
fieldId: FIELD_FUNCTION_NAME_ID,
|
|
332
|
+
item: { id: node.id, language: userLang, version: 0 },
|
|
333
|
+
},
|
|
334
|
+
value: t.functionName,
|
|
335
|
+
rawValue: t.functionName,
|
|
336
|
+
refresh: "delayed",
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
// Set Label
|
|
340
|
+
await editContext.operations.editField({
|
|
341
|
+
field: {
|
|
342
|
+
fieldId: FIELD_LABEL_ID,
|
|
343
|
+
item: { id: node.id, language: userLang, version: 0 },
|
|
344
|
+
},
|
|
345
|
+
value: t.label,
|
|
346
|
+
rawValue: t.label,
|
|
347
|
+
refresh: "delayed",
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
// Set Description
|
|
351
|
+
if (t.description) {
|
|
352
|
+
await editContext.operations.editField({
|
|
353
|
+
field: {
|
|
354
|
+
fieldId: FIELD_DESCRIPTION_ID,
|
|
355
|
+
item: { id: node.id, language: userLang, version: 0 },
|
|
356
|
+
},
|
|
357
|
+
value: t.description,
|
|
358
|
+
rawValue: t.description,
|
|
359
|
+
refresh: "delayed",
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
setAiState("success");
|
|
365
|
+
editContext.requestRefresh?.("immediate");
|
|
366
|
+
} catch (e: any) {
|
|
367
|
+
setToolsError(e?.message || "Failed to generate AI tools");
|
|
368
|
+
} finally {
|
|
369
|
+
setToolsBusy(false);
|
|
370
|
+
}
|
|
371
|
+
}, [editContext, resolvePathUnderContent, userLang]);
|
|
372
|
+
|
|
88
373
|
const createAiEndpoint = useCallback(async () => {
|
|
89
374
|
if (!aiProvider || !editContext) return;
|
|
90
375
|
try {
|
|
@@ -243,7 +528,8 @@ export function AiSetupStep() {
|
|
|
243
528
|
modelTemplateId,
|
|
244
529
|
modelName,
|
|
245
530
|
);
|
|
246
|
-
if (!createdModel)
|
|
531
|
+
if (!createdModel)
|
|
532
|
+
throw new Error(`Failed to create model '${modelName}'`);
|
|
247
533
|
modelNode = {
|
|
248
534
|
id: createdModel.id,
|
|
249
535
|
name: modelName,
|
|
@@ -300,7 +586,10 @@ export function AiSetupStep() {
|
|
|
300
586
|
for (const rc of requiredContainers) initialStates[rc.name] = "checking";
|
|
301
587
|
setContainerStates(initialStates);
|
|
302
588
|
|
|
303
|
-
const settingsItem = await resolvePathUnderContent([
|
|
589
|
+
const settingsItem = await resolvePathUnderContent([
|
|
590
|
+
"Settings",
|
|
591
|
+
"Editor",
|
|
592
|
+
]);
|
|
304
593
|
if (!settingsItem) {
|
|
305
594
|
setEditorSettingsItem(null);
|
|
306
595
|
const errorMsg = "Editor settings item not found. Create it first.";
|
|
@@ -374,39 +663,54 @@ export function AiSetupStep() {
|
|
|
374
663
|
{requiredContainers
|
|
375
664
|
.filter((rc) => containerStates[rc.name] === "error")
|
|
376
665
|
.map((rc) => (
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
</span>
|
|
393
|
-
</div>
|
|
394
|
-
{containerStates[rc.name] !== "success" && (
|
|
395
|
-
<Button
|
|
396
|
-
size="sm"
|
|
397
|
-
onClick={() => createContainer(rc.name, rc.templateId)}
|
|
398
|
-
disabled={!editorSettingsItem || !!busyMap[rc.name]}
|
|
399
|
-
>
|
|
400
|
-
{busyMap[rc.name] ? (
|
|
401
|
-
<RefreshCw strokeWidth={1} className="h-4 w-4 animate-spin" />
|
|
666
|
+
<div
|
|
667
|
+
key={rc.name}
|
|
668
|
+
className="flex items-center justify-between gap-2"
|
|
669
|
+
>
|
|
670
|
+
<div className="flex items-center gap-2">
|
|
671
|
+
{containerStates[rc.name] === "checking" ? (
|
|
672
|
+
<RefreshCw
|
|
673
|
+
strokeWidth={1}
|
|
674
|
+
className="h-4 w-4 animate-spin text-amber-600"
|
|
675
|
+
/>
|
|
676
|
+
) : containerStates[rc.name] === "success" ? (
|
|
677
|
+
<CheckCircle
|
|
678
|
+
strokeWidth={1}
|
|
679
|
+
className="h-4 w-4 text-green-600"
|
|
680
|
+
/>
|
|
402
681
|
) : (
|
|
403
|
-
<
|
|
682
|
+
<AlertCircle
|
|
683
|
+
strokeWidth={1}
|
|
684
|
+
className="h-4 w-4 text-red-600"
|
|
685
|
+
/>
|
|
404
686
|
)}
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
687
|
+
<span className="text-sm text-gray-700">
|
|
688
|
+
{containerStates[rc.name] === "checking"
|
|
689
|
+
? `Checking ${rc.name}...`
|
|
690
|
+
: containerStates[rc.name] === "success"
|
|
691
|
+
? `${rc.name} present`
|
|
692
|
+
: `${rc.name} missing`}
|
|
693
|
+
</span>
|
|
694
|
+
</div>
|
|
695
|
+
{containerStates[rc.name] !== "success" && (
|
|
696
|
+
<Button
|
|
697
|
+
size="sm"
|
|
698
|
+
onClick={() => createContainer(rc.name, rc.templateId)}
|
|
699
|
+
disabled={!editorSettingsItem || !!busyMap[rc.name]}
|
|
700
|
+
>
|
|
701
|
+
{busyMap[rc.name] ? (
|
|
702
|
+
<RefreshCw
|
|
703
|
+
strokeWidth={1}
|
|
704
|
+
className="h-4 w-4 animate-spin"
|
|
705
|
+
/>
|
|
706
|
+
) : (
|
|
707
|
+
<CheckCircle strokeWidth={1} className="h-4 w-4" />
|
|
708
|
+
)}
|
|
709
|
+
Fix
|
|
710
|
+
</Button>
|
|
711
|
+
)}
|
|
712
|
+
</div>
|
|
713
|
+
))}
|
|
410
714
|
</div>
|
|
411
715
|
{containersError && (
|
|
412
716
|
<div className="mt-2 rounded border border-yellow-200 bg-yellow-50 p-2 text-xs whitespace-pre-wrap text-yellow-800">
|
|
@@ -450,6 +754,24 @@ export function AiSetupStep() {
|
|
|
450
754
|
Add endpoint
|
|
451
755
|
</Button>
|
|
452
756
|
</div>
|
|
757
|
+
<div className="mt-4 flex items-center gap-2">
|
|
758
|
+
<Button
|
|
759
|
+
size="sm"
|
|
760
|
+
variant="outline"
|
|
761
|
+
disabled={toolsBusy}
|
|
762
|
+
onClick={ensureAiToolsAndGenerate}
|
|
763
|
+
>
|
|
764
|
+
{toolsBusy ? (
|
|
765
|
+
<RefreshCw strokeWidth={1} className="h-4 w-4 animate-spin" />
|
|
766
|
+
) : (
|
|
767
|
+
<CheckCircle strokeWidth={1} className="h-4 w-4" />
|
|
768
|
+
)}
|
|
769
|
+
Generate AI tool items
|
|
770
|
+
</Button>
|
|
771
|
+
{toolsError && (
|
|
772
|
+
<span className="text-xs text-red-600">{toolsError}</span>
|
|
773
|
+
)}
|
|
774
|
+
</div>
|
|
453
775
|
{aiError && (
|
|
454
776
|
<div className="mt-2 rounded border border-red-200 bg-red-50 p-2 text-xs whitespace-pre-wrap text-red-700">
|
|
455
777
|
{aiError}
|
|
@@ -114,8 +114,9 @@ export function DateFieldEditor({
|
|
|
114
114
|
<Button
|
|
115
115
|
variant="outline"
|
|
116
116
|
data-empty={!date}
|
|
117
|
+
size="sm"
|
|
117
118
|
className={cn(
|
|
118
|
-
"bg-gray-5 justify-start p-
|
|
119
|
+
"bg-gray-5 h-7.5 justify-start p-0 text-left text-xs font-normal",
|
|
119
120
|
!date && "text-muted-foreground",
|
|
120
121
|
)}
|
|
121
122
|
disabled={readOnly}
|
|
@@ -250,7 +250,7 @@ export function DateTimeFieldEditor({
|
|
|
250
250
|
<PopoverTrigger asChild>
|
|
251
251
|
<Button
|
|
252
252
|
variant="ghost"
|
|
253
|
-
className="bg-gray-5 h-
|
|
253
|
+
className="bg-gray-5 h-7.5 w-12 text-xs"
|
|
254
254
|
disabled={readOnly || !date}
|
|
255
255
|
>
|
|
256
256
|
{minutes.toString().padStart(2, "0")}
|
|
@@ -42,11 +42,13 @@ export function DropLinkEditor({
|
|
|
42
42
|
}, [field, editContext.sessionId]);
|
|
43
43
|
|
|
44
44
|
// Convert ItemIdAndName[] to SelectOption[] - memoized to prevent recreation
|
|
45
|
-
const selectOptions: SelectOption[] = useMemo(
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
45
|
+
const selectOptions: SelectOption[] = useMemo(
|
|
46
|
+
() =>
|
|
47
|
+
lazyItems.map((item) => ({
|
|
48
|
+
value: item.id,
|
|
49
|
+
label: item.name,
|
|
50
|
+
})),
|
|
51
|
+
[lazyItems],
|
|
50
52
|
);
|
|
51
53
|
|
|
52
54
|
return (
|
|
@@ -61,7 +63,7 @@ export function DropLinkEditor({
|
|
|
61
63
|
options={selectOptions}
|
|
62
64
|
placeholder="Select"
|
|
63
65
|
disabled={readOnly}
|
|
64
|
-
className="md:w-14rem w-full"
|
|
66
|
+
className="md:w-14rem w-full rounded-sm"
|
|
65
67
|
loading={lazyLoading}
|
|
66
68
|
onLazyLoad={onLazyLoad}
|
|
67
69
|
emptyMessage="No options available"
|
|
@@ -43,17 +43,19 @@ export function DropListEditor({
|
|
|
43
43
|
}, [field, editContext.sessionId]);
|
|
44
44
|
|
|
45
45
|
// Convert ItemIdAndName[] to SelectOption[] using name for both value and label - memoized
|
|
46
|
-
const selectOptions: SelectOption[] = useMemo(
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
46
|
+
const selectOptions: SelectOption[] = useMemo(
|
|
47
|
+
() =>
|
|
48
|
+
lazyItems.map((item) => ({
|
|
49
|
+
value: item.name,
|
|
50
|
+
label: item.name,
|
|
51
|
+
})),
|
|
52
|
+
[lazyItems],
|
|
51
53
|
);
|
|
52
54
|
|
|
53
55
|
// Find the current value or show unknown value - memoized
|
|
54
|
-
const currentValue = useMemo(
|
|
55
|
-
lazyItems.find((o) => o.name === field.value)?.name || field.value,
|
|
56
|
-
[lazyItems, field.value]
|
|
56
|
+
const currentValue = useMemo(
|
|
57
|
+
() => lazyItems.find((o) => o.name === field.value)?.name || field.value,
|
|
58
|
+
[lazyItems, field.value],
|
|
57
59
|
);
|
|
58
60
|
|
|
59
61
|
return (
|
|
@@ -68,7 +70,7 @@ export function DropListEditor({
|
|
|
68
70
|
options={selectOptions}
|
|
69
71
|
placeholder="Select"
|
|
70
72
|
disabled={readOnly}
|
|
71
|
-
className="md:w-14rem w-full"
|
|
73
|
+
className="md:w-14rem w-full rounded-sm"
|
|
72
74
|
loading={lazyLoading}
|
|
73
75
|
onLazyLoad={onLazyLoad}
|
|
74
76
|
emptyMessage="No options available"
|
|
@@ -121,7 +121,7 @@ export function InternalLinkFieldEditor({
|
|
|
121
121
|
<PopoverTrigger asChild disabled={readOnly}>
|
|
122
122
|
<div
|
|
123
123
|
className={classNames(
|
|
124
|
-
"justiy-between focus-shadow bg-gray-5 flex cursor-pointer justify-between border p-1.5 text-xs",
|
|
124
|
+
"justiy-between focus-shadow bg-gray-5 flex cursor-pointer justify-between rounded-sm border p-1.5 text-xs",
|
|
125
125
|
readOnly ? "cursor-default bg-gray-100" : "",
|
|
126
126
|
)}
|
|
127
127
|
>
|
|
@@ -6,6 +6,7 @@ import { Link, LinkEditorDialog } from "../LinkEditorDialog";
|
|
|
6
6
|
import { useEditContext } from "../client/editContext";
|
|
7
7
|
import { LinkField } from "../fieldTypes";
|
|
8
8
|
import { classNames } from "primereact/utils";
|
|
9
|
+
import { Link as LinkIcon } from "lucide-react";
|
|
9
10
|
|
|
10
11
|
export function LinkFieldEditor({
|
|
11
12
|
field,
|
|
@@ -44,7 +45,7 @@ export function LinkFieldEditor({
|
|
|
44
45
|
}}
|
|
45
46
|
>
|
|
46
47
|
<div>{field.value.url}</div>
|
|
47
|
-
<
|
|
48
|
+
<LinkIcon className="h-4 w-4" strokeWidth={1} />
|
|
48
49
|
</div>
|
|
49
50
|
{showDialog && (
|
|
50
51
|
<LinkEditorDialog
|