@alpaca-editor/core 1.0.3902 → 1.0.3904
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/CardConnector.d.ts +2 -1
- package/dist/components/ui/CardConnector.js +3 -3
- package/dist/components/ui/CardConnector.js.map +1 -1
- package/dist/components/ui/button.js +1 -1
- package/dist/components/ui/button.js.map +1 -1
- package/dist/components/ui/card.d.ts +7 -1
- package/dist/components/ui/card.js +71 -3
- package/dist/components/ui/card.js.map +1 -1
- package/dist/config/config.js +4 -2
- package/dist/config/config.js.map +1 -1
- package/dist/config/types.d.ts +1 -0
- package/dist/editor/MobileLayout.js +1 -1
- package/dist/editor/MobileLayout.js.map +1 -1
- package/dist/editor/PictureEditor.js +13 -5
- package/dist/editor/PictureEditor.js.map +1 -1
- package/dist/editor/client/EditorClient.js +2 -2
- package/dist/editor/client/EditorClient.js.map +1 -1
- package/dist/editor/client/editContext.d.ts +14 -1
- package/dist/editor/client/editContext.js.map +1 -1
- package/dist/editor/client/operations.js +1 -1
- package/dist/editor/client/operations.js.map +1 -1
- package/dist/editor/page-editor-chrome/CommentHighlighting.js +4 -1
- package/dist/editor/page-editor-chrome/CommentHighlighting.js.map +1 -1
- package/dist/editor/ui/Splitter.js +3 -1
- package/dist/editor/ui/Splitter.js.map +1 -1
- package/dist/page-wizard/WizardBoxConnector.d.ts +2 -1
- package/dist/page-wizard/WizardBoxConnector.js +3 -3
- package/dist/page-wizard/WizardBoxConnector.js.map +1 -1
- package/dist/page-wizard/WizardSteps.js +63 -17
- package/dist/page-wizard/WizardSteps.js.map +1 -1
- package/dist/page-wizard/service.d.ts +1 -1
- package/dist/page-wizard/service.js +1 -1
- package/dist/page-wizard/service.js.map +1 -1
- package/dist/page-wizard/steps/CollectStep.js +11 -17
- package/dist/page-wizard/steps/CollectStep.js.map +1 -1
- package/dist/page-wizard/steps/ComponentTypesSelector.d.ts +1 -0
- package/dist/page-wizard/steps/ComponentTypesSelector.js +53 -78
- package/dist/page-wizard/steps/ComponentTypesSelector.js.map +1 -1
- package/dist/page-wizard/steps/ContentStep.d.ts +2 -0
- package/dist/page-wizard/steps/ContentStep.js +403 -0
- package/dist/page-wizard/steps/ContentStep.js.map +1 -0
- package/dist/page-wizard/steps/Generate.js +1 -1
- package/dist/page-wizard/steps/Generate.js.map +1 -1
- package/dist/page-wizard/steps/ImagesStep.js +16 -13
- package/dist/page-wizard/steps/ImagesStep.js.map +1 -1
- package/dist/page-wizard/steps/SelectStep.js +1 -1
- package/dist/page-wizard/steps/SelectStep.js.map +1 -1
- package/dist/page-wizard/steps/SetupPageStep.d.ts +2 -0
- package/dist/page-wizard/steps/SetupPageStep.js +152 -0
- package/dist/page-wizard/steps/SetupPageStep.js.map +1 -0
- package/dist/page-wizard/steps/usePageCreator.js +4 -4
- package/dist/page-wizard/steps/usePageCreator.js.map +1 -1
- package/dist/page-wizard/usePageWizard.d.ts +17 -3
- package/dist/page-wizard/usePageWizard.js +62 -2
- package/dist/page-wizard/usePageWizard.js.map +1 -1
- package/dist/revision.d.ts +2 -2
- package/dist/revision.js +2 -2
- package/dist/splash-screen/NewPage.js +10 -10
- package/dist/splash-screen/NewPage.js.map +1 -1
- package/dist/splash-screen/SplashScreen.js +3 -3
- package/dist/splash-screen/SplashScreen.js.map +1 -1
- package/dist/styles.css +184 -68
- package/package.json +1 -1
- package/src/components/ui/CardConnector.tsx +50 -15
- package/src/components/ui/button.tsx +1 -1
- package/src/components/ui/card.tsx +331 -15
- package/src/config/config.tsx +4 -2
- package/src/config/types.ts +3 -0
- package/src/editor/MobileLayout.tsx +7 -9
- package/src/editor/PictureEditor.tsx +16 -10
- package/src/editor/client/EditorClient.tsx +3 -5
- package/src/editor/client/editContext.ts +23 -1
- package/src/editor/client/operations.ts +1 -1
- package/src/editor/page-editor-chrome/CommentHighlighting.tsx +6 -1
- package/src/editor/ui/Splitter.tsx +10 -1
- package/src/page-wizard/WizardBoxConnector.tsx +50 -15
- package/src/page-wizard/WizardSteps.tsx +163 -34
- package/src/page-wizard/service.ts +2 -2
- package/src/page-wizard/steps/CollectStep.tsx +95 -141
- package/src/page-wizard/steps/ComponentTypesSelector.tsx +225 -245
- package/src/page-wizard/steps/ContentStep.tsx +648 -0
- package/src/page-wizard/steps/Generate.tsx +3 -3
- package/src/page-wizard/steps/ImagesStep.tsx +20 -15
- package/src/page-wizard/steps/SelectStep.tsx +4 -4
- package/src/page-wizard/steps/SetupPageStep.tsx +329 -0
- package/src/page-wizard/steps/usePageCreator.ts +4 -4
- package/src/page-wizard/usePageWizard.ts +69 -4
- package/src/revision.ts +2 -2
- package/src/splash-screen/NewPage.tsx +22 -16
- package/src/splash-screen/SplashScreen.tsx +3 -1
- package/dist/page-wizard/steps/CreatePage.d.ts +0 -12
- package/dist/page-wizard/steps/CreatePage.js +0 -149
- package/dist/page-wizard/steps/CreatePage.js.map +0 -1
- package/dist/page-wizard/steps/CreatePageAndLayoutStep.d.ts +0 -2
- package/dist/page-wizard/steps/CreatePageAndLayoutStep.js +0 -235
- package/dist/page-wizard/steps/CreatePageAndLayoutStep.js.map +0 -1
- package/src/page-wizard/steps/CreatePage.tsx +0 -329
- package/src/page-wizard/steps/CreatePageAndLayoutStep.tsx +0 -430
|
@@ -1,430 +0,0 @@
|
|
|
1
|
-
import { StepComponentProps } from "../../config/types";
|
|
2
|
-
|
|
3
|
-
import { CreatePage } from "./CreatePage";
|
|
4
|
-
import { useEffect, useState } from "react";
|
|
5
|
-
import { PageViewer } from "../../editor/page-viewer/PageViewer";
|
|
6
|
-
import {
|
|
7
|
-
useEditContext,
|
|
8
|
-
useModifiedFieldsContext,
|
|
9
|
-
} from "../../editor/client/editContext";
|
|
10
|
-
|
|
11
|
-
import { ComponentTypeSelector } from "./ComponentTypesSelector";
|
|
12
|
-
import { ActionButton } from "../../components/ActionButton";
|
|
13
|
-
import { convertPageSchemaToWizardComponents } from "./schema";
|
|
14
|
-
import { WizardPageModel } from "../PageWizard";
|
|
15
|
-
import { createWizardAiContext, wipeComponents } from "../service";
|
|
16
|
-
|
|
17
|
-
import { executePrompt } from "../../editor/services/aiService";
|
|
18
|
-
import { usePageCreator } from "./usePageCreator";
|
|
19
|
-
import { useThrottledCallback } from "use-debounce";
|
|
20
|
-
import { InputTextarea } from "primereact/inputtextarea";
|
|
21
|
-
|
|
22
|
-
import { convertToAiPageModel } from "../../editor/ai/aiPageModel";
|
|
23
|
-
import { WizardBox } from "../WizardBox";
|
|
24
|
-
import { Layers, PanelsTopLeft } from "lucide-react";
|
|
25
|
-
import { cn } from "../../lib/utils";
|
|
26
|
-
import { WizardBoxConnector } from "../WizardBoxConnector";
|
|
27
|
-
|
|
28
|
-
export function CreatePageAndLayoutStep({
|
|
29
|
-
wizard,
|
|
30
|
-
step,
|
|
31
|
-
parentItem,
|
|
32
|
-
pageModel,
|
|
33
|
-
setPageModel,
|
|
34
|
-
data,
|
|
35
|
-
setData,
|
|
36
|
-
internalState,
|
|
37
|
-
setInternalState,
|
|
38
|
-
setStepCompleted,
|
|
39
|
-
}: StepComponentProps) {
|
|
40
|
-
const [pageLoaded, setPageLoaded] = useState(false);
|
|
41
|
-
const [isLoading, setIsLoading] = useState(false);
|
|
42
|
-
|
|
43
|
-
const editContext = useEditContext();
|
|
44
|
-
const [abortController, setAbortController] = useState<AbortController>();
|
|
45
|
-
const [message, setMessage] = useState<string>();
|
|
46
|
-
const [isCreatingComponents, setIsCreatingComponents] = useState(false);
|
|
47
|
-
const pageItem = internalState.pageItem;
|
|
48
|
-
const modifiedFieldsContext = useModifiedFieldsContext();
|
|
49
|
-
|
|
50
|
-
const pageCreator = usePageCreator(pageItem, wizard, setPageModel);
|
|
51
|
-
|
|
52
|
-
if (!parentItem) return "No parent item";
|
|
53
|
-
|
|
54
|
-
useEffect(() => {
|
|
55
|
-
editContext?.setMode("edit");
|
|
56
|
-
if (!internalState.layoutInstructions) {
|
|
57
|
-
setInternalState({
|
|
58
|
-
...internalState,
|
|
59
|
-
layoutInstructions: step.instructions,
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
|
-
}, []);
|
|
63
|
-
|
|
64
|
-
const createComponents = async () => {
|
|
65
|
-
if (!pageLoaded) return;
|
|
66
|
-
if (pageModel?.components && !isCreatingComponents) {
|
|
67
|
-
try {
|
|
68
|
-
setIsCreatingComponents(true);
|
|
69
|
-
|
|
70
|
-
await pageCreator.createComponentsRecursively(
|
|
71
|
-
pageModel.components,
|
|
72
|
-
"root",
|
|
73
|
-
);
|
|
74
|
-
setInternalState((prev: any) => ({
|
|
75
|
-
...prev,
|
|
76
|
-
componentsCreated: true,
|
|
77
|
-
}));
|
|
78
|
-
} finally {
|
|
79
|
-
setIsCreatingComponents(false);
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
};
|
|
83
|
-
|
|
84
|
-
useEffect(() => {
|
|
85
|
-
if (
|
|
86
|
-
internalState.componentsCreated &&
|
|
87
|
-
!isCreatingComponents &&
|
|
88
|
-
!isLoading
|
|
89
|
-
) {
|
|
90
|
-
editContext?.requestRefresh("immediate");
|
|
91
|
-
}
|
|
92
|
-
}, [isCreatingComponents, isLoading]);
|
|
93
|
-
|
|
94
|
-
const createComponentsThrottled = useThrottledCallback(createComponents, 300);
|
|
95
|
-
|
|
96
|
-
useEffect(() => {
|
|
97
|
-
createComponentsThrottled();
|
|
98
|
-
}, [pageModel]);
|
|
99
|
-
|
|
100
|
-
useEffect(() => {
|
|
101
|
-
if (
|
|
102
|
-
editContext &&
|
|
103
|
-
editContext.page &&
|
|
104
|
-
editContext.page.item &&
|
|
105
|
-
pageItem &&
|
|
106
|
-
pageItem.id === editContext.page.item.descriptor.id
|
|
107
|
-
)
|
|
108
|
-
setPageLoaded(true);
|
|
109
|
-
}, [editContext?.page, pageItem]);
|
|
110
|
-
|
|
111
|
-
if (!pageItem) {
|
|
112
|
-
return (
|
|
113
|
-
<CreatePage
|
|
114
|
-
wizard={wizard}
|
|
115
|
-
parentItem={parentItem}
|
|
116
|
-
setPageItem={(pageItem) =>
|
|
117
|
-
setInternalState((prev: any) => ({ ...prev, pageItem }))
|
|
118
|
-
}
|
|
119
|
-
pageItem={pageItem}
|
|
120
|
-
pageModel={pageModel}
|
|
121
|
-
setPageModel={setPageModel}
|
|
122
|
-
step={step}
|
|
123
|
-
data={data}
|
|
124
|
-
/>
|
|
125
|
-
);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
const createLayout = async () => {
|
|
129
|
-
try {
|
|
130
|
-
if (!editContext) return;
|
|
131
|
-
|
|
132
|
-
setIsLoading(true);
|
|
133
|
-
setStepCompleted(false);
|
|
134
|
-
|
|
135
|
-
if (internalState.componentsCreated) {
|
|
136
|
-
editContext?.itemsRepository.clear();
|
|
137
|
-
modifiedFieldsContext?.clear();
|
|
138
|
-
await wipeComponents(pageItem.descriptor);
|
|
139
|
-
|
|
140
|
-
setPageModel((prev) => ({
|
|
141
|
-
...prev,
|
|
142
|
-
components: [],
|
|
143
|
-
message: "",
|
|
144
|
-
}));
|
|
145
|
-
|
|
146
|
-
editContext?.requestRefresh("immediate");
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
// Parse schema if it's a string
|
|
150
|
-
const schema =
|
|
151
|
-
typeof wizard.schema === "string"
|
|
152
|
-
? JSON.parse(wizard.schema)
|
|
153
|
-
: wizard.schema;
|
|
154
|
-
|
|
155
|
-
// Filter the schema based on selected component types and placeholders
|
|
156
|
-
const filteredSchema = convertPageSchemaToWizardComponents(
|
|
157
|
-
schema,
|
|
158
|
-
data.selectedComponentTypes,
|
|
159
|
-
);
|
|
160
|
-
|
|
161
|
-
const localAbortController = new AbortController();
|
|
162
|
-
setAbortController(localAbortController);
|
|
163
|
-
|
|
164
|
-
// Get the existing page model
|
|
165
|
-
const existingPageModel = await convertToAiPageModel(
|
|
166
|
-
editContext.page!,
|
|
167
|
-
editContext,
|
|
168
|
-
);
|
|
169
|
-
|
|
170
|
-
const result = await executePrompt(
|
|
171
|
-
[
|
|
172
|
-
{
|
|
173
|
-
content: `${internalState.layoutInstructions?.trim()} Reply with a json object of type PageModel = { components: Component[]; message: string; };
|
|
174
|
-
Component = { id: string | undefined, name: string, type: string; fields: Field[]; placeholder?: string; children?: Component[]; };
|
|
175
|
-
Field = { name: string; value: string; type: string; };
|
|
176
|
-
Generate a descriptive name for each component including the topic.
|
|
177
|
-
Only use component types that are in the page schema.
|
|
178
|
-
Keep existing components with their ids. Leave id field empty for new components.
|
|
179
|
-
Existing page model: ${JSON.stringify(existingPageModel)}
|
|
180
|
-
Fill empty fields of existing components before you insert new components.
|
|
181
|
-
Component types: ${JSON.stringify(
|
|
182
|
-
filteredSchema,
|
|
183
|
-
)} Root level component types ${filteredSchema
|
|
184
|
-
.filter((c) => c.allowedOnRoot)
|
|
185
|
-
.map((c) => c.type)
|
|
186
|
-
.join(", ")}
|
|
187
|
-
Tell the user your reasoning in the message field.
|
|
188
|
-
If the user provided image ids, fill them into picture / image fields with an "id:" prefix. The image id needs to be guid.
|
|
189
|
-
If you dont have a matching image id, provide a description of a picture that you would like to use with a "generate:" prefix instead.
|
|
190
|
-
The language of the page is ${pageItem.descriptor.language}.
|
|
191
|
-
Input data: ${JSON.stringify(data)}`,
|
|
192
|
-
|
|
193
|
-
name: "system",
|
|
194
|
-
role: "system",
|
|
195
|
-
},
|
|
196
|
-
], //Fill image ids into picture / image fields.
|
|
197
|
-
editContext,
|
|
198
|
-
createWizardAiContext,
|
|
199
|
-
{ allowedFunctions: [] },
|
|
200
|
-
{ signal: localAbortController.signal },
|
|
201
|
-
step.aiModel || "o3-mini-low",
|
|
202
|
-
(response) => {
|
|
203
|
-
try {
|
|
204
|
-
const newLayout = JSON.parse(response.content) as WizardPageModel;
|
|
205
|
-
|
|
206
|
-
if (newLayout) {
|
|
207
|
-
setPageModel((prev) => mergeLayout(prev, newLayout));
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
setMessage(newLayout.message);
|
|
211
|
-
} catch (parseError: unknown) {}
|
|
212
|
-
},
|
|
213
|
-
);
|
|
214
|
-
|
|
215
|
-
const pageModel = result;
|
|
216
|
-
|
|
217
|
-
console.log("RESULT MODEL: ", pageModel);
|
|
218
|
-
|
|
219
|
-
setPageModel((prev) => mergeLayout(prev, pageModel));
|
|
220
|
-
setMessage(pageModel.message);
|
|
221
|
-
setStepCompleted(true);
|
|
222
|
-
} catch (error) {
|
|
223
|
-
console.error(error);
|
|
224
|
-
} finally {
|
|
225
|
-
setIsLoading(false);
|
|
226
|
-
}
|
|
227
|
-
};
|
|
228
|
-
|
|
229
|
-
// Custom instructions panel
|
|
230
|
-
const customInstructionsPanel = () => {
|
|
231
|
-
return (
|
|
232
|
-
<div className="mb-4">
|
|
233
|
-
<h3 className="text-sm font-semibold">Instructions</h3>
|
|
234
|
-
<div className="mb-3 text-xs text-gray-500">
|
|
235
|
-
Provide guidance for the AI when generating your layout
|
|
236
|
-
</div>
|
|
237
|
-
<InputTextarea
|
|
238
|
-
value={internalState.layoutInstructions}
|
|
239
|
-
onChange={(e) =>
|
|
240
|
-
setInternalState({
|
|
241
|
-
...internalState,
|
|
242
|
-
layoutInstructions: e.target.value,
|
|
243
|
-
})
|
|
244
|
-
}
|
|
245
|
-
placeholder="Example: Make it modern and minimalist. Focus on images. Include a hero section at the top."
|
|
246
|
-
className="h-48 w-full rounded border border-gray-300 px-3 py-2 text-sm focus:ring-1 focus:ring-blue-500 focus:outline-none"
|
|
247
|
-
/>
|
|
248
|
-
</div>
|
|
249
|
-
);
|
|
250
|
-
};
|
|
251
|
-
|
|
252
|
-
return (
|
|
253
|
-
<div className="flex h-full">
|
|
254
|
-
<WizardBox
|
|
255
|
-
title="Generate content"
|
|
256
|
-
icon={<Layers />}
|
|
257
|
-
description="Generate content for the page"
|
|
258
|
-
className="w-96"
|
|
259
|
-
>
|
|
260
|
-
<div className="flex h-full flex-col items-stretch">
|
|
261
|
-
<div className="relative flex-1">
|
|
262
|
-
<div className="absolute inset-0 overflow-y-auto pr-6">
|
|
263
|
-
<div className="text-sm font-medium">Page item</div>
|
|
264
|
-
<div className="text-xs text-gray-500">{pageItem.path}</div>
|
|
265
|
-
<ComponentTypeSelector
|
|
266
|
-
selectedComponentTypes={data.selectedComponentTypes}
|
|
267
|
-
setSelectedComponentTypes={(selectedTypes) => {
|
|
268
|
-
setData({
|
|
269
|
-
...data,
|
|
270
|
-
selectedComponentTypes: selectedTypes,
|
|
271
|
-
});
|
|
272
|
-
}}
|
|
273
|
-
schema={wizard.schema}
|
|
274
|
-
data={data}
|
|
275
|
-
setData={setData}
|
|
276
|
-
step={step}
|
|
277
|
-
/>
|
|
278
|
-
{customInstructionsPanel()}
|
|
279
|
-
</div>
|
|
280
|
-
</div>
|
|
281
|
-
<div className="py-2">
|
|
282
|
-
<div className="flex w-full gap-2">
|
|
283
|
-
<ActionButton
|
|
284
|
-
onClick={createLayout}
|
|
285
|
-
disabled={
|
|
286
|
-
isLoading ||
|
|
287
|
-
isCreatingComponents ||
|
|
288
|
-
!data.selectedComponentTypes ||
|
|
289
|
-
data.selectedComponentTypes.length === 0
|
|
290
|
-
}
|
|
291
|
-
isLoading={
|
|
292
|
-
isLoading ||
|
|
293
|
-
isCreatingComponents ||
|
|
294
|
-
!!editContext?.activeFieldActions.find(
|
|
295
|
-
(action) => action.state === "running",
|
|
296
|
-
)
|
|
297
|
-
}
|
|
298
|
-
loadingText="Working"
|
|
299
|
-
className="w-full flex-1"
|
|
300
|
-
>
|
|
301
|
-
{internalState.componentsCreated
|
|
302
|
-
? "Reset and regenerate content"
|
|
303
|
-
: "Generate content"}
|
|
304
|
-
</ActionButton>
|
|
305
|
-
|
|
306
|
-
{isLoading && (
|
|
307
|
-
<ActionButton
|
|
308
|
-
isLoading={false}
|
|
309
|
-
onClick={() => abortController?.abort("User aborted")}
|
|
310
|
-
>
|
|
311
|
-
Abort
|
|
312
|
-
</ActionButton>
|
|
313
|
-
)}
|
|
314
|
-
</div>
|
|
315
|
-
{message && <div className="mt-2 text-xs">{message}</div>}
|
|
316
|
-
</div>
|
|
317
|
-
</div>
|
|
318
|
-
</WizardBox>
|
|
319
|
-
<WizardBoxConnector className="mt-6" />
|
|
320
|
-
<WizardBox
|
|
321
|
-
title="Page preview"
|
|
322
|
-
icon={<PanelsTopLeft />}
|
|
323
|
-
description="After finalizing the page, you can edit, further enhance the content and share the page with your team for collaboration."
|
|
324
|
-
noPadding={true}
|
|
325
|
-
className="flex-1"
|
|
326
|
-
>
|
|
327
|
-
<div
|
|
328
|
-
className={cn(
|
|
329
|
-
"border-t border-gray-200",
|
|
330
|
-
pageLoaded ? "h-full" : "h-0",
|
|
331
|
-
)}
|
|
332
|
-
>
|
|
333
|
-
<PageViewer
|
|
334
|
-
name="single"
|
|
335
|
-
compareView={false}
|
|
336
|
-
showFormEditor={false}
|
|
337
|
-
followEditsDefault={true}
|
|
338
|
-
pageViewContext={editContext!.pageView}
|
|
339
|
-
/>
|
|
340
|
-
</div>
|
|
341
|
-
</WizardBox>
|
|
342
|
-
</div>
|
|
343
|
-
);
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
/**
|
|
347
|
-
* Merges a new layout with the previous layout
|
|
348
|
-
* - Keeps all previous components
|
|
349
|
-
* - Adds new components
|
|
350
|
-
* - Updates existing fields with new values
|
|
351
|
-
* - Adds new fields
|
|
352
|
-
*/
|
|
353
|
-
const mergeLayout = (
|
|
354
|
-
prev: WizardPageModel | null,
|
|
355
|
-
newLayout: WizardPageModel,
|
|
356
|
-
): WizardPageModel => {
|
|
357
|
-
if (!prev) return newLayout;
|
|
358
|
-
|
|
359
|
-
// Merge top-level properties
|
|
360
|
-
const result: WizardPageModel = {
|
|
361
|
-
name: newLayout.name || prev.name,
|
|
362
|
-
message: newLayout.message,
|
|
363
|
-
metaDescription: prev.metaDescription,
|
|
364
|
-
metaKeywords: prev.metaKeywords,
|
|
365
|
-
components: [...(prev.components || [])],
|
|
366
|
-
};
|
|
367
|
-
|
|
368
|
-
// Function to merge components recursively
|
|
369
|
-
const mergeComponents = (
|
|
370
|
-
existingComponents: any[],
|
|
371
|
-
newComponents: any[],
|
|
372
|
-
): any[] => {
|
|
373
|
-
if (!newComponents?.length) return existingComponents;
|
|
374
|
-
|
|
375
|
-
const result = [...existingComponents];
|
|
376
|
-
|
|
377
|
-
for (const newComp of newComponents) {
|
|
378
|
-
// Try to find a matching component by type and name
|
|
379
|
-
const existingIndex = result.findIndex(
|
|
380
|
-
(comp) => comp.type === newComp.type && comp.name === newComp.name,
|
|
381
|
-
);
|
|
382
|
-
|
|
383
|
-
if (existingIndex >= 0) {
|
|
384
|
-
// Update existing component
|
|
385
|
-
const existing = result[existingIndex];
|
|
386
|
-
|
|
387
|
-
// Merge fields - update existing fields and add new ones
|
|
388
|
-
const mergedFields = [...(existing.fields || [])];
|
|
389
|
-
for (const newField of newComp.fields || []) {
|
|
390
|
-
const fieldIndex = mergedFields.findIndex(
|
|
391
|
-
(f) => f.name === newField.name,
|
|
392
|
-
);
|
|
393
|
-
if (fieldIndex >= 0) {
|
|
394
|
-
mergedFields[fieldIndex].value = newField.value; // Update existing field
|
|
395
|
-
mergedFields[fieldIndex].type = newField.type;
|
|
396
|
-
} else {
|
|
397
|
-
mergedFields.push(newField); // Add new field
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
// Recursive merge of children components
|
|
402
|
-
const mergedChildren = mergeComponents(
|
|
403
|
-
existing.children || [],
|
|
404
|
-
newComp.children || [],
|
|
405
|
-
);
|
|
406
|
-
|
|
407
|
-
// Create updated component
|
|
408
|
-
result[existingIndex] = {
|
|
409
|
-
...existing,
|
|
410
|
-
fields: mergedFields,
|
|
411
|
-
children: mergedChildren,
|
|
412
|
-
placeholder: newComp.placeholder || existing.placeholder,
|
|
413
|
-
};
|
|
414
|
-
} else {
|
|
415
|
-
// Add new component
|
|
416
|
-
result.push(newComp);
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
return result;
|
|
421
|
-
};
|
|
422
|
-
|
|
423
|
-
// Merge components recursively
|
|
424
|
-
result.components = mergeComponents(
|
|
425
|
-
result.components,
|
|
426
|
-
newLayout.components || [],
|
|
427
|
-
);
|
|
428
|
-
|
|
429
|
-
return result;
|
|
430
|
-
};
|