@alpaca-editor/core 1.0.4017 → 1.0.4026
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/SimpleLanguageSelector.d.ts +2 -1
- package/dist/components/SimpleLanguageSelector.js +9 -2
- package/dist/components/SimpleLanguageSelector.js.map +1 -1
- package/dist/components/ui/input.js +1 -1
- package/dist/components/ui/input.js.map +1 -1
- package/dist/components/ui/tooltip.d.ts +3 -1
- package/dist/components/ui/tooltip.js +2 -2
- package/dist/components/ui/tooltip.js.map +1 -1
- package/dist/config/config.js +4 -0
- package/dist/config/config.js.map +1 -1
- package/dist/config/types.d.ts +2 -0
- package/dist/editor/ContentTree.js +1 -1
- package/dist/editor/ContentTree.js.map +1 -1
- package/dist/editor/ContextMenu.js +26 -0
- package/dist/editor/ContextMenu.js.map +1 -1
- package/dist/editor/FieldHistory.js +1 -1
- package/dist/editor/FieldHistory.js.map +1 -1
- package/dist/editor/FieldListField.js +2 -2
- package/dist/editor/FieldListField.js.map +1 -1
- package/dist/editor/Terminal.js +3 -1
- package/dist/editor/Terminal.js.map +1 -1
- package/dist/editor/ai/Agents.js +19 -10
- package/dist/editor/ai/Agents.js.map +1 -1
- package/dist/editor/ai/AiResponseMessage.js +63 -5
- package/dist/editor/ai/AiResponseMessage.js.map +1 -1
- package/dist/editor/ai/AiTerminal.js +7 -7
- package/dist/editor/ai/AiTerminal.js.map +1 -1
- package/dist/editor/ai/AiToolCall.js +3 -3
- package/dist/editor/ai/AiToolCall.js.map +1 -1
- package/dist/editor/client/EditorClient.js +5 -1
- package/dist/editor/client/EditorClient.js.map +1 -1
- package/dist/editor/client/editContext.d.ts +2 -0
- package/dist/editor/client/editContext.js.map +1 -1
- package/dist/editor/client/operations.d.ts +1 -0
- package/dist/editor/client/operations.js +7 -0
- package/dist/editor/client/operations.js.map +1 -1
- package/dist/editor/commands/componentCommands.js +1 -1
- package/dist/editor/commands/componentCommands.js.map +1 -1
- package/dist/editor/field-types/ImageFieldEditor.js +1 -1
- package/dist/editor/field-types/ImageFieldEditor.js.map +1 -1
- package/dist/editor/field-types/MultiLineText.js +1 -1
- package/dist/editor/field-types/MultiLineText.js.map +1 -1
- package/dist/editor/field-types/PictureFieldEditor.js +1 -1
- package/dist/editor/field-types/PictureFieldEditor.js.map +1 -1
- package/dist/editor/field-types/RawEditor.js +1 -1
- package/dist/editor/field-types/RawEditor.js.map +1 -1
- package/dist/editor/field-types/RichTextEditorComponent.js +16 -17
- package/dist/editor/field-types/RichTextEditorComponent.js.map +1 -1
- package/dist/editor/field-types/SingleLineText.js +1 -1
- package/dist/editor/field-types/SingleLineText.js.map +1 -1
- package/dist/editor/field-types/richtext/components/SimpleDropdown.d.ts +18 -0
- package/dist/editor/field-types/richtext/components/SimpleDropdown.js +71 -0
- package/dist/editor/field-types/richtext/components/SimpleDropdown.js.map +1 -0
- package/dist/editor/field-types/richtext/components/SimpleRichTextEditor.d.ts +5 -0
- package/dist/editor/field-types/richtext/components/SimpleRichTextEditor.js +359 -0
- package/dist/editor/field-types/richtext/components/SimpleRichTextEditor.js.map +1 -0
- package/dist/editor/field-types/richtext/components/SimpleToolbar.d.ts +16 -0
- package/dist/editor/field-types/richtext/components/SimpleToolbar.js +181 -0
- package/dist/editor/field-types/richtext/components/SimpleToolbar.js.map +1 -0
- package/dist/editor/field-types/richtext/components/SimpleToolbarButton.d.ts +9 -0
- package/dist/editor/field-types/richtext/components/SimpleToolbarButton.js +14 -0
- package/dist/editor/field-types/richtext/components/SimpleToolbarButton.js.map +1 -0
- package/dist/editor/field-types/richtext/contextMenuFactory.d.ts +4 -0
- package/dist/editor/field-types/richtext/contextMenuFactory.js +193 -0
- package/dist/editor/field-types/richtext/contextMenuFactory.js.map +1 -0
- package/dist/editor/field-types/richtext/index.d.ts +6 -5
- package/dist/editor/field-types/richtext/index.js +6 -5
- package/dist/editor/field-types/richtext/index.js.map +1 -1
- package/dist/editor/field-types/richtext/types.d.ts +16 -16
- package/dist/editor/field-types/richtext/types.js +84 -84
- package/dist/editor/field-types/richtext/types.js.map +1 -1
- package/dist/editor/page-editor-chrome/CommentHighlighting.js +1 -1
- package/dist/editor/page-editor-chrome/CommentHighlighting.js.map +1 -1
- package/dist/editor/page-editor-chrome/FrameMenu.js +5 -5
- package/dist/editor/page-editor-chrome/FrameMenu.js.map +1 -1
- package/dist/editor/page-editor-chrome/PlaceholderDropZone.js +1 -1
- package/dist/editor/page-viewer/PageViewerFrame.js +3 -2
- package/dist/editor/page-viewer/PageViewerFrame.js.map +1 -1
- package/dist/editor/services/agentService.d.ts +14 -4
- package/dist/editor/services/agentService.js.map +1 -1
- package/dist/editor/services/aiService.js +1 -0
- package/dist/editor/services/aiService.js.map +1 -1
- package/dist/page-wizard/PageWizard.d.ts +2 -0
- package/dist/page-wizard/PageWizard.js +6 -13
- package/dist/page-wizard/PageWizard.js.map +1 -1
- package/dist/page-wizard/WizardSteps.js +3 -1
- package/dist/page-wizard/WizardSteps.js.map +1 -1
- package/dist/page-wizard/service.d.ts +1 -0
- package/dist/page-wizard/service.js +7 -0
- package/dist/page-wizard/service.js.map +1 -1
- package/dist/page-wizard/steps/ContentStep.js +210 -33
- package/dist/page-wizard/steps/ContentStep.js.map +1 -1
- package/dist/page-wizard/steps/FindItemsStep.js +11 -3
- package/dist/page-wizard/steps/FindItemsStep.js.map +1 -1
- package/dist/page-wizard/steps/LayoutStep.js +1 -1
- package/dist/page-wizard/steps/LayoutStep.js.map +1 -1
- package/dist/page-wizard/steps/MetaDataStep.js +1 -1
- package/dist/page-wizard/steps/MetaDataStep.js.map +1 -1
- package/dist/page-wizard/steps/SchottSelectImagesStep.d.ts +2 -0
- package/dist/page-wizard/steps/SchottSelectImagesStep.js +55 -0
- package/dist/page-wizard/steps/SchottSelectImagesStep.js.map +1 -0
- package/dist/page-wizard/steps/StructureStep.js +20 -5
- package/dist/page-wizard/steps/StructureStep.js.map +1 -1
- package/dist/page-wizard/steps/TranslateStep.d.ts +2 -0
- package/dist/page-wizard/steps/TranslateStep.js +413 -0
- package/dist/page-wizard/steps/TranslateStep.js.map +1 -0
- package/dist/page-wizard/utils/dataAccessor.d.ts +7 -0
- package/dist/page-wizard/utils/dataAccessor.js +76 -0
- 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/splash-screen/NewPage.js +5 -4
- package/dist/splash-screen/NewPage.js.map +1 -1
- package/dist/splash-screen/OpenPage.js +2 -1
- package/dist/splash-screen/OpenPage.js.map +1 -1
- package/dist/splash-screen/RecentPages.js +3 -1
- package/dist/splash-screen/RecentPages.js.map +1 -1
- package/dist/styles.css +57 -0
- package/package.json +5 -4
- package/src/components/SimpleLanguageSelector.tsx +11 -1
- package/src/components/ui/input.tsx +1 -1
- package/src/components/ui/tooltip.tsx +3 -2
- package/src/config/config.tsx +4 -0
- package/src/config/types.ts +6 -0
- package/src/editor/ContentTree.tsx +1 -1
- package/src/editor/ContextMenu.tsx +39 -0
- package/src/editor/FieldHistory.tsx +1 -1
- package/src/editor/FieldListField.tsx +2 -6
- package/src/editor/Terminal.tsx +5 -1
- package/src/editor/ai/Agents.tsx +27 -16
- package/src/editor/ai/AiResponseMessage.tsx +138 -23
- package/src/editor/ai/AiTerminal.tsx +43 -29
- package/src/editor/ai/AiToolCall.tsx +14 -4
- package/src/editor/client/EditorClient.tsx +9 -1
- package/src/editor/client/editContext.ts +2 -0
- package/src/editor/client/operations.ts +9 -0
- package/src/editor/commands/componentCommands.tsx +1 -1
- package/src/editor/field-types/ImageFieldEditor.tsx +1 -0
- package/src/editor/field-types/MultiLineText.tsx +1 -0
- package/src/editor/field-types/PictureFieldEditor.tsx +1 -0
- package/src/editor/field-types/RawEditor.tsx +1 -0
- package/src/editor/field-types/RichTextEditorComponent.tsx +27 -25
- package/src/editor/field-types/SingleLineText.tsx +1 -0
- package/src/editor/field-types/richtext/components/SimpleDropdown.tsx +165 -0
- package/src/editor/field-types/richtext/components/SimpleRichTextEditor.css +261 -0
- package/src/editor/field-types/richtext/components/SimpleRichTextEditor.tsx +505 -0
- package/src/editor/field-types/richtext/components/SimpleToolbar.tsx +362 -0
- package/src/editor/field-types/richtext/components/SimpleToolbarButton.tsx +36 -0
- package/src/editor/field-types/richtext/contextMenuFactory.tsx +264 -0
- package/src/editor/field-types/richtext/index.ts +6 -5
- package/src/editor/field-types/richtext/types.ts +168 -148
- package/src/editor/page-editor-chrome/CommentHighlighting.tsx +1 -1
- package/src/editor/page-editor-chrome/FrameMenu.tsx +16 -11
- package/src/editor/page-editor-chrome/PlaceholderDropZone.tsx +1 -1
- package/src/editor/page-viewer/PageViewerFrame.tsx +4 -3
- package/src/editor/services/agentService.ts +16 -5
- package/src/editor/services/aiService.ts +2 -0
- package/src/page-wizard/PageWizard.tsx +10 -13
- package/src/page-wizard/WizardSteps.tsx +3 -1
- package/src/page-wizard/service.ts +11 -0
- package/src/page-wizard/steps/ContentStep.tsx +376 -43
- package/src/page-wizard/steps/FindItemsStep.tsx +23 -3
- package/src/page-wizard/steps/LayoutStep.tsx +1 -1
- package/src/page-wizard/steps/MetaDataStep.tsx +1 -1
- package/src/page-wizard/steps/SchottSelectImagesStep.tsx +141 -0
- package/src/page-wizard/steps/StructureStep.tsx +40 -5
- package/src/page-wizard/steps/TranslateStep.tsx +772 -0
- package/src/page-wizard/utils/dataAccessor.ts +85 -0
- package/src/revision.ts +2 -2
- package/src/splash-screen/NewPage.tsx +18 -3
- package/src/splash-screen/OpenPage.tsx +14 -1
- package/src/splash-screen/RecentPages.tsx +4 -2
- package/tsconfig.build.json +1 -0
|
@@ -25,10 +25,13 @@ import { executePrompt } from "../../editor/services/aiService";
|
|
|
25
25
|
import { usePageCreator } from "./usePageCreator";
|
|
26
26
|
import { useThrottledCallback } from "use-debounce";
|
|
27
27
|
import { InputTextarea } from "primereact/inputtextarea";
|
|
28
|
-
import {
|
|
28
|
+
import { Input } from "../../components/ui/input";
|
|
29
29
|
import { LanguageSelector } from "../../editor/menubar/LanguageSelector";
|
|
30
30
|
import { EditControls } from "../../editor/menubar/toolbar-sections/EditControls";
|
|
31
|
-
import {
|
|
31
|
+
import {
|
|
32
|
+
getFilteredInputData,
|
|
33
|
+
processPromptTemplate,
|
|
34
|
+
} from "../utils/dataAccessor";
|
|
32
35
|
|
|
33
36
|
import { WizardBox } from "../WizardBox";
|
|
34
37
|
import { Wand2, PanelsTopLeft, Settings, Blocks } from "lucide-react";
|
|
@@ -36,6 +39,16 @@ import { cn } from "../../lib/utils";
|
|
|
36
39
|
import { WizardBoxConnector } from "../WizardBoxConnector";
|
|
37
40
|
import { ItemDescriptor, FullItem } from "../../editor/pageModel";
|
|
38
41
|
import Generate from "./Generate";
|
|
42
|
+
import {
|
|
43
|
+
Popover,
|
|
44
|
+
PopoverContent,
|
|
45
|
+
PopoverTrigger,
|
|
46
|
+
} from "../../components/ui/popover";
|
|
47
|
+
import { ChevronDown, Folder, Trash } from "lucide-react";
|
|
48
|
+
import { ScrollingContentTree } from "../../editor/ScrollingContentTree";
|
|
49
|
+
import ItemSearch from "../../editor/ui/ItemSearch";
|
|
50
|
+
import { normalizeGuid } from "../../editor/utils";
|
|
51
|
+
import { classNames } from "primereact/utils";
|
|
39
52
|
|
|
40
53
|
export function ContentStep({
|
|
41
54
|
wizard,
|
|
@@ -69,20 +82,170 @@ export function ContentStep({
|
|
|
69
82
|
parentItem?.language || "en",
|
|
70
83
|
);
|
|
71
84
|
const [fullParentItem, setFullParentItem] = useState<FullItem>();
|
|
85
|
+
|
|
72
86
|
const [nameValidation, setNameValidation] = useState<{
|
|
73
87
|
isValid: boolean;
|
|
74
88
|
message?: string;
|
|
75
89
|
}>({ isValid: false });
|
|
76
90
|
|
|
91
|
+
// Add target folder selection state
|
|
92
|
+
const [targetFolder, setTargetFolder] = useState<ItemDescriptor | null>(
|
|
93
|
+
parentItem || null,
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
const [isSelectingFolder, setIsSelectingFolder] = useState(false);
|
|
97
|
+
const [folderSelectionResult, setFolderSelectionResult] = useState<{
|
|
98
|
+
id: string;
|
|
99
|
+
path: string;
|
|
100
|
+
} | null>(null);
|
|
101
|
+
const [showFolderTree, setShowFolderTree] = useState(false);
|
|
102
|
+
|
|
77
103
|
const modifiedFieldsContext = useModifiedFieldsContext();
|
|
78
104
|
|
|
79
105
|
const pageCreator = usePageCreator(pageItem, wizard, setPageModel);
|
|
80
106
|
|
|
81
107
|
if (!parentItem) return "No parent item";
|
|
82
108
|
|
|
109
|
+
// Add target folder selection function
|
|
110
|
+
const selectTargetItem = useCallback(async () => {
|
|
111
|
+
if (!editContext || !step.fields.targetItemPrompt) return;
|
|
112
|
+
|
|
113
|
+
setIsSelectingFolder(true);
|
|
114
|
+
|
|
115
|
+
try {
|
|
116
|
+
const abortController = new AbortController();
|
|
117
|
+
|
|
118
|
+
const prompt = step.fields.targetItemPrompt;
|
|
119
|
+
|
|
120
|
+
// Process template expressions in the folder selection prompt
|
|
121
|
+
const templateResult = processPromptTemplate(prompt, data);
|
|
122
|
+
|
|
123
|
+
console.log("ContentStep: templateResult", prompt, templateResult.value);
|
|
124
|
+
|
|
125
|
+
if (templateResult.error) {
|
|
126
|
+
console.error(
|
|
127
|
+
"Template processing error in target item prompt:",
|
|
128
|
+
templateResult.error,
|
|
129
|
+
);
|
|
130
|
+
setMessage(`Template Error: ${templateResult.error}`);
|
|
131
|
+
setIsSelectingFolder(false);
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const processedPrompt = templateResult.value;
|
|
136
|
+
|
|
137
|
+
const result = await executePrompt(
|
|
138
|
+
[
|
|
139
|
+
{
|
|
140
|
+
content: `${processedPrompt?.trim()}
|
|
141
|
+
You can use get-children to explore existing items and create-item to create new items if needed.
|
|
142
|
+
Reply with a json object of type { id: string; path: string; } containing the ID and path of the target item.
|
|
143
|
+
The language of the content is ${language}.
|
|
144
|
+
Current parent item: ${fullParentItem?.path || parentItem?.id}
|
|
145
|
+
`,
|
|
146
|
+
name: "system",
|
|
147
|
+
role: "system",
|
|
148
|
+
id: crypto.randomUUID(),
|
|
149
|
+
},
|
|
150
|
+
],
|
|
151
|
+
{ editContext, createAiContext: createWizardAiContext },
|
|
152
|
+
{
|
|
153
|
+
allowedFunctions: ["get-children", "create-item"],
|
|
154
|
+
model: step.fields.aiModel || "gpt-4.1",
|
|
155
|
+
},
|
|
156
|
+
{ signal: abortController.signal },
|
|
157
|
+
(response) => {
|
|
158
|
+
try {
|
|
159
|
+
const folderResult = JSON.parse(response.content) as {
|
|
160
|
+
id: string;
|
|
161
|
+
path: string;
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
if (folderResult.id && folderResult.path) {
|
|
165
|
+
setFolderSelectionResult(folderResult);
|
|
166
|
+
// Update target folder with the selected folder
|
|
167
|
+
setTargetFolder({
|
|
168
|
+
id: folderResult.id,
|
|
169
|
+
language: language,
|
|
170
|
+
} as ItemDescriptor);
|
|
171
|
+
}
|
|
172
|
+
} catch (parseError: unknown) {}
|
|
173
|
+
},
|
|
174
|
+
);
|
|
175
|
+
|
|
176
|
+
if (result && result.messages && result.messages.length > 0) {
|
|
177
|
+
const lastMessage = result.messages[result.messages.length - 1];
|
|
178
|
+
if (lastMessage && lastMessage.content) {
|
|
179
|
+
const folderResult = JSON.parse(lastMessage.content) as {
|
|
180
|
+
id: string;
|
|
181
|
+
path: string;
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
if (folderResult.id && folderResult.path) {
|
|
185
|
+
setFolderSelectionResult(folderResult);
|
|
186
|
+
// Update target folder with the selected folder
|
|
187
|
+
setTargetFolder({
|
|
188
|
+
id: folderResult.id,
|
|
189
|
+
language: language,
|
|
190
|
+
} as ItemDescriptor);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
} catch (error) {
|
|
195
|
+
console.error("Error selecting target folder", error);
|
|
196
|
+
} finally {
|
|
197
|
+
setIsSelectingFolder(false);
|
|
198
|
+
}
|
|
199
|
+
}, [
|
|
200
|
+
editContext,
|
|
201
|
+
step.fields.selectTargetFolderPrompt,
|
|
202
|
+
language,
|
|
203
|
+
parentItem,
|
|
204
|
+
data,
|
|
205
|
+
]);
|
|
206
|
+
|
|
207
|
+
const handleFolderSelection = useCallback(
|
|
208
|
+
async (folderId: string) => {
|
|
209
|
+
if (!editContext) return;
|
|
210
|
+
|
|
211
|
+
try {
|
|
212
|
+
const folderItem = await editContext.itemsRepository.getItem({
|
|
213
|
+
id: folderId,
|
|
214
|
+
language: language,
|
|
215
|
+
version: 0,
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
if (folderItem) {
|
|
219
|
+
setTargetFolder({
|
|
220
|
+
id: folderId,
|
|
221
|
+
language: language,
|
|
222
|
+
} as ItemDescriptor);
|
|
223
|
+
|
|
224
|
+
setFolderSelectionResult({
|
|
225
|
+
id: folderId,
|
|
226
|
+
path: folderItem.path,
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
setFullParentItem(folderItem);
|
|
230
|
+
setShowFolderTree(false);
|
|
231
|
+
}
|
|
232
|
+
} catch (error) {
|
|
233
|
+
console.error("Error loading selected folder:", error);
|
|
234
|
+
}
|
|
235
|
+
},
|
|
236
|
+
[editContext, language],
|
|
237
|
+
);
|
|
238
|
+
|
|
239
|
+
const clearFolderSelection = useCallback(() => {
|
|
240
|
+
setTargetFolder(parentItem);
|
|
241
|
+
setFolderSelectionResult(null);
|
|
242
|
+
setFullParentItem(undefined);
|
|
243
|
+
setShowFolderTree(false);
|
|
244
|
+
}, [parentItem]);
|
|
245
|
+
|
|
83
246
|
const checkPageName = useCallback(async () => {
|
|
84
|
-
if (!
|
|
85
|
-
setNameValidation({ isValid: false, message: "No
|
|
247
|
+
if (!targetFolder) {
|
|
248
|
+
setNameValidation({ isValid: false, message: "No target folder" });
|
|
86
249
|
return false;
|
|
87
250
|
}
|
|
88
251
|
|
|
@@ -98,7 +261,7 @@ export function ContentStep({
|
|
|
98
261
|
try {
|
|
99
262
|
// Check if page with same name already exists
|
|
100
263
|
const children = await getChildren(
|
|
101
|
-
|
|
264
|
+
targetFolder.id,
|
|
102
265
|
editContext?.sessionId ?? "",
|
|
103
266
|
[],
|
|
104
267
|
false,
|
|
@@ -129,7 +292,7 @@ export function ContentStep({
|
|
|
129
292
|
return false;
|
|
130
293
|
}
|
|
131
294
|
}, [
|
|
132
|
-
|
|
295
|
+
targetFolder,
|
|
133
296
|
pageModel.name,
|
|
134
297
|
editContext?.sessionId,
|
|
135
298
|
editContext?.contentEditorItem?.language,
|
|
@@ -145,7 +308,7 @@ export function ContentStep({
|
|
|
145
308
|
};
|
|
146
309
|
|
|
147
310
|
const createPageIfNeeded = useCallback(async (): Promise<boolean> => {
|
|
148
|
-
if (!editContext || !
|
|
311
|
+
if (!editContext || !targetFolder || pageItem) return true; // Page already exists
|
|
149
312
|
|
|
150
313
|
try {
|
|
151
314
|
if (!(await checkPageName())) {
|
|
@@ -155,8 +318,8 @@ export function ContentStep({
|
|
|
155
318
|
|
|
156
319
|
const result = await editContext.operations.createItem(
|
|
157
320
|
{
|
|
158
|
-
...getItemDescriptor(
|
|
159
|
-
language:
|
|
321
|
+
...getItemDescriptor(targetFolder),
|
|
322
|
+
language: targetFolder.language || "en",
|
|
160
323
|
},
|
|
161
324
|
wizard.templateId,
|
|
162
325
|
pageModel.name,
|
|
@@ -180,7 +343,7 @@ export function ContentStep({
|
|
|
180
343
|
}
|
|
181
344
|
}, [
|
|
182
345
|
editContext,
|
|
183
|
-
|
|
346
|
+
targetFolder,
|
|
184
347
|
pageItem,
|
|
185
348
|
checkPageName,
|
|
186
349
|
wizard.templateId,
|
|
@@ -302,17 +465,19 @@ export function ContentStep({
|
|
|
302
465
|
}
|
|
303
466
|
}, [pageModel.name, checkPageName]);
|
|
304
467
|
|
|
305
|
-
// Load
|
|
468
|
+
// Load target folder details
|
|
306
469
|
useEffect(() => {
|
|
307
|
-
const
|
|
308
|
-
if (!
|
|
309
|
-
const item = await editContext?.itemsRepository.getItem(
|
|
470
|
+
const loadTargetItem = async () => {
|
|
471
|
+
if (!targetFolder) return;
|
|
472
|
+
const item = await editContext?.itemsRepository.getItem(targetFolder);
|
|
473
|
+
setFullParentItem(item);
|
|
474
|
+
// Also set fullParentItem for backward compatibility
|
|
310
475
|
setFullParentItem(item);
|
|
311
476
|
};
|
|
312
|
-
|
|
313
|
-
}, [parentItem]);
|
|
477
|
+
loadTargetItem();
|
|
478
|
+
}, [parentItem, editContext]);
|
|
314
479
|
|
|
315
|
-
// Auto-generate page name and
|
|
480
|
+
// Auto-generate page name and select target folder if not set
|
|
316
481
|
useEffect(() => {
|
|
317
482
|
if (!editContext) return;
|
|
318
483
|
|
|
@@ -326,19 +491,37 @@ export function ContentStep({
|
|
|
326
491
|
try {
|
|
327
492
|
const abortController = new AbortController();
|
|
328
493
|
|
|
494
|
+
// Process template expressions in the prompt
|
|
495
|
+
const templateResult = processPromptTemplate(
|
|
496
|
+
pageNameInstructions,
|
|
497
|
+
data,
|
|
498
|
+
);
|
|
499
|
+
|
|
500
|
+
if (templateResult.error) {
|
|
501
|
+
console.error(
|
|
502
|
+
"Template processing error in page name prompt:",
|
|
503
|
+
templateResult.error,
|
|
504
|
+
);
|
|
505
|
+
setMessage(`Template Error: ${templateResult.error}`);
|
|
506
|
+
setIsGenerating(false);
|
|
507
|
+
return;
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
const processedInstructions = templateResult.value;
|
|
511
|
+
|
|
329
512
|
const result = await executePrompt(
|
|
330
513
|
[
|
|
331
514
|
{
|
|
332
|
-
content: `${
|
|
515
|
+
content: `${processedInstructions?.trim()} Reply with a json object of type PageModel = { name: string; };
|
|
333
516
|
The language of the page is ${language}.
|
|
334
|
-
|
|
517
|
+
`,
|
|
335
518
|
name: "system",
|
|
336
519
|
role: "system",
|
|
337
520
|
id: crypto.randomUUID(), // Use proper UUID instead of Date.now()
|
|
338
521
|
},
|
|
339
522
|
],
|
|
340
523
|
{ editContext, createAiContext: createWizardAiContext },
|
|
341
|
-
{ model: "
|
|
524
|
+
{ model: step.fields.aiModel || "gpt-4.1" },
|
|
342
525
|
{ signal: abortController.signal },
|
|
343
526
|
(response) => {
|
|
344
527
|
try {
|
|
@@ -371,8 +554,33 @@ export function ContentStep({
|
|
|
371
554
|
}
|
|
372
555
|
};
|
|
373
556
|
|
|
374
|
-
|
|
375
|
-
|
|
557
|
+
// Run page name generation and folder selection in parallel
|
|
558
|
+
const runInitialGeneration = async () => {
|
|
559
|
+
const promises = [];
|
|
560
|
+
|
|
561
|
+
// Generate page name if not set
|
|
562
|
+
if (!pageModel.name) {
|
|
563
|
+
promises.push(generatePageName());
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
// Select target folder if prompt is configured and folder not yet selected
|
|
567
|
+
if (step.fields.targetItemPrompt && !folderSelectionResult) {
|
|
568
|
+
promises.push(selectTargetItem());
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
// Run both in parallel
|
|
572
|
+
if (promises.length > 0) {
|
|
573
|
+
await Promise.all(promises);
|
|
574
|
+
}
|
|
575
|
+
};
|
|
576
|
+
|
|
577
|
+
runInitialGeneration();
|
|
578
|
+
}, [
|
|
579
|
+
pageModel.name,
|
|
580
|
+
folderSelectionResult,
|
|
581
|
+
step.fields.targetItemPrompt,
|
|
582
|
+
selectTargetItem,
|
|
583
|
+
]);
|
|
376
584
|
|
|
377
585
|
const createComponents = async () => {
|
|
378
586
|
if (!pageLoaded) return;
|
|
@@ -562,9 +770,27 @@ export function ContentStep({
|
|
|
562
770
|
// Filter input data based on "Input Properties" field if specified
|
|
563
771
|
const inputData = getFilteredInputData(step, data);
|
|
564
772
|
|
|
773
|
+
// Process template expressions in the layout instructions
|
|
774
|
+
const templateResult = processPromptTemplate(
|
|
775
|
+
internalState.layoutInstructions || "",
|
|
776
|
+
data,
|
|
777
|
+
);
|
|
778
|
+
|
|
779
|
+
if (templateResult.error) {
|
|
780
|
+
console.error(
|
|
781
|
+
"Template processing error in layout instructions:",
|
|
782
|
+
templateResult.error,
|
|
783
|
+
);
|
|
784
|
+
setMessage(`Template Error: ${templateResult.error}`);
|
|
785
|
+
setIsLoading(false);
|
|
786
|
+
return;
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
const processedInstructions = templateResult.value;
|
|
790
|
+
|
|
565
791
|
const prompt = [
|
|
566
792
|
{
|
|
567
|
-
content: `${
|
|
793
|
+
content: `${processedInstructions ? processedInstructions?.trim() : ""} Reply with a json object of type PageModel = { fields: Field[]; components: Component[]; message: string; };
|
|
568
794
|
Component = { id: string | undefined, name: string, type: string; fields: Field[]; placeholder?: string; children?: Component[]; };
|
|
569
795
|
Field = { name: string; value: string; type: string; };
|
|
570
796
|
Generate a descriptive name for each component including the topic.
|
|
@@ -588,7 +814,7 @@ export function ContentStep({
|
|
|
588
814
|
Tell the user your reasoning in the message field.
|
|
589
815
|
|
|
590
816
|
The language of the page is ${editContextRef.current!.page!.item!.language}.
|
|
591
|
-
|
|
817
|
+
`,
|
|
592
818
|
|
|
593
819
|
name: "system",
|
|
594
820
|
role: "system",
|
|
@@ -596,12 +822,6 @@ export function ContentStep({
|
|
|
596
822
|
},
|
|
597
823
|
];
|
|
598
824
|
|
|
599
|
-
console.log("PAGE WIZARD DATA: ", data);
|
|
600
|
-
console.log("PAGE WIZARD INPUTDATA: ", inputData);
|
|
601
|
-
console.log("PAGE WIZARD PROMPT: ", prompt?.[0]?.content);
|
|
602
|
-
console.log("PAGE WIZARD page fields: ", schema.pageFields);
|
|
603
|
-
console.log("PAGE WIZARD schema: ", filteredSchema);
|
|
604
|
-
|
|
605
825
|
const result = await executePrompt(
|
|
606
826
|
prompt,
|
|
607
827
|
{
|
|
@@ -672,7 +892,9 @@ export function ContentStep({
|
|
|
672
892
|
collapsible="yes"
|
|
673
893
|
summary={
|
|
674
894
|
<div className="flex flex-col gap-2 text-xs break-all text-gray-500">
|
|
675
|
-
<div>
|
|
895
|
+
<div>
|
|
896
|
+
Folder: {folderSelectionResult?.path || fullParentItem?.path}
|
|
897
|
+
</div>
|
|
676
898
|
<div>Language: {language}</div>
|
|
677
899
|
<div>Name: {pageModel.name || "Not set"}</div>
|
|
678
900
|
</div>
|
|
@@ -681,24 +903,33 @@ export function ContentStep({
|
|
|
681
903
|
>
|
|
682
904
|
<div className="flex flex-col items-stretch">
|
|
683
905
|
<div className="relative flex-1">
|
|
684
|
-
{isGenerating ? (
|
|
906
|
+
{isGenerating || isSelectingFolder ? (
|
|
685
907
|
<div className="mt-4 flex h-full items-center justify-center pb-4">
|
|
686
|
-
<Generate
|
|
908
|
+
<Generate
|
|
909
|
+
title={
|
|
910
|
+
isGenerating && isSelectingFolder
|
|
911
|
+
? "Generating page name and selecting folder..."
|
|
912
|
+
: isGenerating
|
|
913
|
+
? "Generating page name..."
|
|
914
|
+
: "Selecting folder..."
|
|
915
|
+
}
|
|
916
|
+
size="medium"
|
|
917
|
+
/>
|
|
687
918
|
</div>
|
|
688
919
|
) : (
|
|
689
920
|
<>
|
|
690
921
|
<div className="mb-4">
|
|
691
922
|
<label
|
|
692
923
|
htmlFor="pageName"
|
|
693
|
-
className="mb-1 block text-
|
|
924
|
+
className="mb-1 block text-xs font-medium"
|
|
694
925
|
>
|
|
695
926
|
Page Name
|
|
696
927
|
</label>
|
|
697
|
-
<
|
|
928
|
+
<Input
|
|
698
929
|
id="pageName"
|
|
699
930
|
type="text"
|
|
700
931
|
disabled={!!pageItem}
|
|
701
|
-
className={`w-full rounded border
|
|
932
|
+
className={`bg-gray-5 w-full rounded border md:text-xs ${
|
|
702
933
|
!nameValidation.isValid
|
|
703
934
|
? "border-red-500"
|
|
704
935
|
: nameValidation.isValid && pageModel.name
|
|
@@ -706,7 +937,7 @@ export function ContentStep({
|
|
|
706
937
|
: ""
|
|
707
938
|
}`}
|
|
708
939
|
value={pageModel.name}
|
|
709
|
-
onChange={(e) =>
|
|
940
|
+
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
|
|
710
941
|
handleInputChange("name", e.target.value)
|
|
711
942
|
}
|
|
712
943
|
placeholder="Enter page name"
|
|
@@ -724,12 +955,106 @@ export function ContentStep({
|
|
|
724
955
|
</div>
|
|
725
956
|
|
|
726
957
|
<div className="mb-4">
|
|
727
|
-
<div className="mb-1 text-
|
|
728
|
-
Target
|
|
729
|
-
</div>
|
|
730
|
-
<div className="mb-4 break-after-all text-xs text-gray-600">
|
|
731
|
-
{fullParentItem?.path || "Loading..."}
|
|
958
|
+
<div className="mb-1 text-xs font-medium">
|
|
959
|
+
Target Folder
|
|
732
960
|
</div>
|
|
961
|
+
{isSelectingFolder ? (
|
|
962
|
+
<div className="mb-4 flex items-center gap-2 text-xs text-gray-600">
|
|
963
|
+
<Generate title="Selecting folder..." size="medium" />
|
|
964
|
+
Selecting folder...
|
|
965
|
+
</div>
|
|
966
|
+
) : (
|
|
967
|
+
<div className="mb-4">
|
|
968
|
+
<div className="relative">
|
|
969
|
+
<Popover
|
|
970
|
+
open={showFolderTree}
|
|
971
|
+
onOpenChange={setShowFolderTree}
|
|
972
|
+
>
|
|
973
|
+
<PopoverTrigger asChild>
|
|
974
|
+
<div
|
|
975
|
+
className={classNames(
|
|
976
|
+
"focus-shadow bg-gray-5 flex cursor-pointer justify-between border p-1.5 text-xs hover:bg-gray-100",
|
|
977
|
+
)}
|
|
978
|
+
>
|
|
979
|
+
<div className="flex items-center gap-2">
|
|
980
|
+
<Folder className="h-4 w-4" strokeWidth={1} />
|
|
981
|
+
<span className="break-all">
|
|
982
|
+
{folderSelectionResult?.path ||
|
|
983
|
+
fullParentItem?.path ||
|
|
984
|
+
"Loading..."}
|
|
985
|
+
</span>
|
|
986
|
+
</div>
|
|
987
|
+
<ChevronDown
|
|
988
|
+
strokeWidth={1}
|
|
989
|
+
className={`h-4 w-4 transition-transform duration-200 ${
|
|
990
|
+
showFolderTree ? "rotate-180" : "rotate-0"
|
|
991
|
+
}`}
|
|
992
|
+
/>
|
|
993
|
+
</div>
|
|
994
|
+
</PopoverTrigger>
|
|
995
|
+
|
|
996
|
+
<PopoverContent
|
|
997
|
+
className="w-96 p-0"
|
|
998
|
+
align="start"
|
|
999
|
+
side="bottom"
|
|
1000
|
+
>
|
|
1001
|
+
<div className="border-b border-gray-200 bg-white p-2">
|
|
1002
|
+
<ItemSearch
|
|
1003
|
+
rootItemIds={[
|
|
1004
|
+
normalizeGuid(
|
|
1005
|
+
parentItem?.id ||
|
|
1006
|
+
"11111111-1111-1111-1111-111111111111",
|
|
1007
|
+
),
|
|
1008
|
+
]}
|
|
1009
|
+
autoFocus={true}
|
|
1010
|
+
itemSelected={(item) => {
|
|
1011
|
+
handleFolderSelection(item.id);
|
|
1012
|
+
}}
|
|
1013
|
+
/>
|
|
1014
|
+
</div>
|
|
1015
|
+
|
|
1016
|
+
{folderSelectionResult && (
|
|
1017
|
+
<button
|
|
1018
|
+
className="w-full cursor-pointer rounded border-b bg-gray-50 p-1 px-4 text-left text-xs hover:bg-gray-100"
|
|
1019
|
+
onClick={clearFolderSelection}
|
|
1020
|
+
>
|
|
1021
|
+
<div className="flex items-center gap-2">
|
|
1022
|
+
<Trash
|
|
1023
|
+
className="h-4 w-4"
|
|
1024
|
+
strokeWidth={1}
|
|
1025
|
+
/>{" "}
|
|
1026
|
+
Reset to original folder
|
|
1027
|
+
</div>
|
|
1028
|
+
</button>
|
|
1029
|
+
)}
|
|
1030
|
+
|
|
1031
|
+
<div className="relative h-64 border-x border-b">
|
|
1032
|
+
<ScrollingContentTree
|
|
1033
|
+
key={`folder-tree-${showFolderTree ? "open" : "closed"}-${targetFolder?.id || "none"}`}
|
|
1034
|
+
selectedItemId={targetFolder?.id}
|
|
1035
|
+
rootItemIds={[
|
|
1036
|
+
parentItem?.id ||
|
|
1037
|
+
"11111111-1111-1111-1111-111111111111",
|
|
1038
|
+
]}
|
|
1039
|
+
expandedItemId={targetFolder?.id}
|
|
1040
|
+
scrollToSelected={true}
|
|
1041
|
+
onSelectionChange={(nodes) => {
|
|
1042
|
+
if (nodes[0]?.id) {
|
|
1043
|
+
handleFolderSelection(nodes[0].id);
|
|
1044
|
+
}
|
|
1045
|
+
}}
|
|
1046
|
+
/>
|
|
1047
|
+
</div>
|
|
1048
|
+
</PopoverContent>
|
|
1049
|
+
</Popover>
|
|
1050
|
+
</div>
|
|
1051
|
+
{step.fields.targetItemPrompt && parentItem && (
|
|
1052
|
+
<div className="mt-1 text-xs text-green-600">
|
|
1053
|
+
✓ Folder selected by AI
|
|
1054
|
+
</div>
|
|
1055
|
+
)}
|
|
1056
|
+
</div>
|
|
1057
|
+
)}
|
|
733
1058
|
</div>
|
|
734
1059
|
|
|
735
1060
|
<div className="relative mb-4">
|
|
@@ -801,6 +1126,7 @@ export function ContentStep({
|
|
|
801
1126
|
disabled={
|
|
802
1127
|
isLoading ||
|
|
803
1128
|
isCreatingComponents ||
|
|
1129
|
+
isSelectingFolder ||
|
|
804
1130
|
!data.selectedComponentTypes ||
|
|
805
1131
|
data.selectedComponentTypes.length === 0 ||
|
|
806
1132
|
(!pageItem &&
|
|
@@ -811,11 +1137,18 @@ export function ContentStep({
|
|
|
811
1137
|
isLoading={
|
|
812
1138
|
isLoading ||
|
|
813
1139
|
isCreatingComponents ||
|
|
1140
|
+
isSelectingFolder ||
|
|
814
1141
|
!!editContext?.activeFieldActions.find(
|
|
815
1142
|
(action) => action.state === "running",
|
|
816
1143
|
)
|
|
817
1144
|
}
|
|
818
|
-
loadingText={
|
|
1145
|
+
loadingText={
|
|
1146
|
+
isSelectingFolder
|
|
1147
|
+
? "Selecting folder..."
|
|
1148
|
+
: isGenerating
|
|
1149
|
+
? "Generating..."
|
|
1150
|
+
: "Working"
|
|
1151
|
+
}
|
|
819
1152
|
className="w-full flex-1"
|
|
820
1153
|
>
|
|
821
1154
|
{!pageItem ? "Create page" : "Delete & Regenerate content"}
|
|
@@ -9,7 +9,11 @@ import {
|
|
|
9
9
|
fetchItemStubs,
|
|
10
10
|
} from "../../editor/services/contentService";
|
|
11
11
|
import { ItemDescriptor } from "../../editor/pageModel";
|
|
12
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
evaluateDataExpression,
|
|
14
|
+
setDataProperty,
|
|
15
|
+
processPromptTemplate,
|
|
16
|
+
} from "../utils/dataAccessor";
|
|
13
17
|
import { executePrompt } from "../../editor/services/aiService";
|
|
14
18
|
import { createWizardAiContext } from "../service";
|
|
15
19
|
import { ActionButton } from "../../components/ActionButton";
|
|
@@ -177,12 +181,28 @@ export function FindItemsStep({
|
|
|
177
181
|
// Evaluate only the input properties that should be included
|
|
178
182
|
const evaluatedInputData = evaluateDataExpression(inputProperties, data);
|
|
179
183
|
|
|
184
|
+
// Process template expressions in system instructions
|
|
185
|
+
const systemInstructionsResult = processPromptTemplate(
|
|
186
|
+
step.fields.systemInstructions || "",
|
|
187
|
+
data,
|
|
188
|
+
);
|
|
189
|
+
|
|
190
|
+
if (systemInstructionsResult.error) {
|
|
191
|
+
console.error(
|
|
192
|
+
"Template processing error in system instructions:",
|
|
193
|
+
systemInstructionsResult.error,
|
|
194
|
+
);
|
|
195
|
+
setAiError(`Template Error: ${systemInstructionsResult.error}`);
|
|
196
|
+
setLoadingAI(false);
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
|
|
180
200
|
const basePrompt = `
|
|
181
|
-
${
|
|
201
|
+
${systemInstructionsResult.value || ""}
|
|
182
202
|
|
|
183
203
|
You need to suggest relevant content items from a content tree. Here are the details:
|
|
184
204
|
|
|
185
|
-
|
|
205
|
+
|
|
186
206
|
Source Root IDs: ${JSON.stringify(rootItemIds)}
|
|
187
207
|
Multi-select: ${multiSelect}
|
|
188
208
|
Max selections needed: ${multiSelect ? "multiple" : "1"}
|
|
@@ -71,7 +71,7 @@ export function LayoutStep({
|
|
|
71
71
|
Where components are of type Component = { id: string; name: string; fields: FieldDefinition[]; styles: string; };
|
|
72
72
|
And fields are of type FieldDefinition = { name: string; type: string; value: string; };
|
|
73
73
|
|
|
74
|
-
|
|
74
|
+
|
|
75
75
|
|
|
76
76
|
Types: Row: Use this to group components horizontally. Section: Use this to group components with a background color or spacing. Title: Use for titles and headings. Text: Use for general text content. Quote: Use for quotes and callouts. Image: Use for images and media. TeaserList: Use for lists of items with images and descriptions. Test: Component for testing and prototyping.
|
|
77
77
|
|
|
@@ -62,7 +62,7 @@ export function MetaDataStep({
|
|
|
62
62
|
{
|
|
63
63
|
content: `${metaInstructions?.trim()} Reply with a json object of type PageModel = { metaDescription: string; metaKeywords: string; };
|
|
64
64
|
The language of the page is ${parentItem?.language || "en"}.
|
|
65
|
-
|
|
65
|
+
`,
|
|
66
66
|
name: "system",
|
|
67
67
|
role: "system",
|
|
68
68
|
id: crypto.randomUUID(), // Use proper UUID instead of Date.now()
|