@firecms/collection_editor 3.1.0-canary.1df3b2c → 3.1.0-canary.7d91b7c
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/index.es.js +372 -325
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +371 -324
- package/dist/index.umd.js.map +1 -1
- package/dist/ui/collection_editor/AICollectionGeneratorPopover.d.ts +5 -1
- package/dist/ui/collection_editor/CollectionEditorDialog.d.ts +4 -0
- package/dist/ui/collection_editor/CollectionEditorWelcomeView.d.ts +2 -1
- package/package.json +12 -12
- package/src/ConfigControllerProvider.tsx +1 -0
- package/src/ui/collection_editor/AICollectionGeneratorPopover.tsx +18 -1
- package/src/ui/collection_editor/CollectionDetailsForm.tsx +3 -2
- package/src/ui/collection_editor/CollectionEditorDialog.tsx +13 -4
- package/src/ui/collection_editor/CollectionEditorWelcomeView.tsx +4 -1
- package/src/ui/collection_editor/GeneralSettingsForm.tsx +9 -7
- package/src/ui/collection_editor/PropertyEditView.tsx +1 -1
|
@@ -29,5 +29,9 @@ export interface AICollectionGeneratorPopoverProps {
|
|
|
29
29
|
* Whether to show the label text
|
|
30
30
|
*/
|
|
31
31
|
showLabel?: boolean;
|
|
32
|
+
/**
|
|
33
|
+
* Optional analytics callback
|
|
34
|
+
*/
|
|
35
|
+
onAnalyticsEvent?: (event: string, params?: object) => void;
|
|
32
36
|
}
|
|
33
|
-
export declare function AICollectionGeneratorPopover({ existingCollection, onGenerated, generateCollection, trigger, size, showLabel }: AICollectionGeneratorPopoverProps): import("react/jsx-runtime").JSX.Element;
|
|
37
|
+
export declare function AICollectionGeneratorPopover({ existingCollection, onGenerated, generateCollection, trigger, size, showLabel, onAnalyticsEvent }: AICollectionGeneratorPopoverProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -48,6 +48,10 @@ export interface CollectionEditorDialogProps {
|
|
|
48
48
|
* The plugin is API-agnostic - the consumer provides the implementation.
|
|
49
49
|
*/
|
|
50
50
|
generateCollection?: CollectionGenerationCallback;
|
|
51
|
+
/**
|
|
52
|
+
* Optional analytics callback
|
|
53
|
+
*/
|
|
54
|
+
onAnalyticsEvent?: (event: string, params?: object) => void;
|
|
51
55
|
}
|
|
52
56
|
export declare function CollectionEditorDialog(props: CollectionEditorDialogProps): import("react/jsx-runtime").JSX.Element;
|
|
53
57
|
export declare function CollectionEditor(props: CollectionEditorDialogProps & {
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { EntityCollection } from "@firecms/core";
|
|
3
3
|
import { CollectionGenerationCallback } from "../../api/generateCollectionApi";
|
|
4
|
-
export declare function CollectionEditorWelcomeView({ path, parentCollection, onContinue, existingCollectionPaths, generateCollection }: {
|
|
4
|
+
export declare function CollectionEditorWelcomeView({ path, parentCollection, onContinue, existingCollectionPaths, generateCollection, onAnalyticsEvent }: {
|
|
5
5
|
path: string;
|
|
6
6
|
parentCollection?: EntityCollection;
|
|
7
7
|
onContinue: (importData?: object[], propertiesOrder?: string[]) => void;
|
|
8
8
|
existingCollectionPaths?: string[];
|
|
9
9
|
generateCollection?: CollectionGenerationCallback;
|
|
10
|
+
onAnalyticsEvent?: (event: string, params?: object) => void;
|
|
10
11
|
}): import("react/jsx-runtime").JSX.Element;
|
|
11
12
|
export declare function TemplateButton({ title, subtitle, icon, onClick }: {
|
|
12
13
|
title: string;
|
package/package.json
CHANGED
|
@@ -1,24 +1,24 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@firecms/collection_editor",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "3.1.0-canary.
|
|
4
|
+
"version": "3.1.0-canary.7d91b7c",
|
|
5
5
|
"main": "./dist/index.umd.js",
|
|
6
6
|
"module": "./dist/index.es.js",
|
|
7
7
|
"types": "./dist/index.d.ts",
|
|
8
8
|
"source": "src/index.ts",
|
|
9
9
|
"dependencies": {
|
|
10
|
-
"@firecms/data_export": "^3.1.0-canary.
|
|
11
|
-
"@firecms/data_import": "^3.1.0-canary.
|
|
12
|
-
"@firecms/data_import_export": "^3.1.0-canary.
|
|
13
|
-
"@firecms/formex": "^3.1.0-canary.
|
|
14
|
-
"@firecms/schema_inference": "^3.1.0-canary.
|
|
15
|
-
"@firecms/ui": "^3.1.0-canary.
|
|
10
|
+
"@firecms/data_export": "^3.1.0-canary.7d91b7c",
|
|
11
|
+
"@firecms/data_import": "^3.1.0-canary.7d91b7c",
|
|
12
|
+
"@firecms/data_import_export": "^3.1.0-canary.7d91b7c",
|
|
13
|
+
"@firecms/formex": "^3.1.0-canary.7d91b7c",
|
|
14
|
+
"@firecms/schema_inference": "^3.1.0-canary.7d91b7c",
|
|
15
|
+
"@firecms/ui": "^3.1.0-canary.7d91b7c",
|
|
16
16
|
"json5": "^2.2.3",
|
|
17
17
|
"prism-react-renderer": "^2.4.1"
|
|
18
18
|
},
|
|
19
19
|
"peerDependencies": {
|
|
20
|
-
"react": ">=18.0.0",
|
|
21
|
-
"react-dom": ">=18.0.0",
|
|
20
|
+
"react": ">=18.3.1 || >=19.0.0",
|
|
21
|
+
"react-dom": ">=18.3.1 || >=19.0.0",
|
|
22
22
|
"react-router": "^6.28.0",
|
|
23
23
|
"react-router-dom": "^6.28.0"
|
|
24
24
|
},
|
|
@@ -50,8 +50,8 @@
|
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
52
|
"@jest/globals": "^30.2.0",
|
|
53
|
-
"@types/react": "^
|
|
54
|
-
"@types/react-dom": "^
|
|
53
|
+
"@types/react": "^19.2.3",
|
|
54
|
+
"@types/react-dom": "^19.2.3",
|
|
55
55
|
"@vitejs/plugin-react": "^4.7.0",
|
|
56
56
|
"babel-plugin-react-compiler": "^19.0.0-beta-af1b7da-20250417",
|
|
57
57
|
"eslint-plugin-react-compiler": "^19.1.0-rc.2",
|
|
@@ -69,5 +69,5 @@
|
|
|
69
69
|
"publishConfig": {
|
|
70
70
|
"access": "public"
|
|
71
71
|
},
|
|
72
|
-
"gitHead": "
|
|
72
|
+
"gitHead": "c444882e108a37a1e90dff02c1c4d58e891ef054"
|
|
73
73
|
}
|
|
@@ -272,6 +272,7 @@ export const ConfigControllerProvider = React.memo(
|
|
|
272
272
|
extraView={extraView}
|
|
273
273
|
getUser={getUser}
|
|
274
274
|
generateCollection={generateCollection}
|
|
275
|
+
onAnalyticsEvent={onAnalyticsEvent}
|
|
275
276
|
handleClose={(collection) => {
|
|
276
277
|
if (currentDialog?.redirect) {
|
|
277
278
|
if (collection && currentDialog?.isNewCollection && !currentDialog.parentCollectionIds.length) {
|
|
@@ -48,6 +48,11 @@ export interface AICollectionGeneratorPopoverProps {
|
|
|
48
48
|
* Whether to show the label text
|
|
49
49
|
*/
|
|
50
50
|
showLabel?: boolean;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Optional analytics callback
|
|
54
|
+
*/
|
|
55
|
+
onAnalyticsEvent?: (event: string, params?: object) => void;
|
|
51
56
|
}
|
|
52
57
|
|
|
53
58
|
export function AICollectionGeneratorPopover({
|
|
@@ -56,7 +61,8 @@ export function AICollectionGeneratorPopover({
|
|
|
56
61
|
generateCollection,
|
|
57
62
|
trigger,
|
|
58
63
|
size = "small",
|
|
59
|
-
showLabel = true
|
|
64
|
+
showLabel = true,
|
|
65
|
+
onAnalyticsEvent
|
|
60
66
|
}: AICollectionGeneratorPopoverProps) {
|
|
61
67
|
const [menuOpen, setMenuOpen] = useState(false);
|
|
62
68
|
const [prompt, setPrompt] = useState("");
|
|
@@ -74,6 +80,9 @@ export function AICollectionGeneratorPopover({
|
|
|
74
80
|
setLoading(true);
|
|
75
81
|
setError(null);
|
|
76
82
|
|
|
83
|
+
const mode = existingCollection ? "modify" : "create";
|
|
84
|
+
onAnalyticsEvent?.("ai_collection_generate_start", { mode });
|
|
85
|
+
|
|
77
86
|
try {
|
|
78
87
|
const collectionsContext = existingCollections.map(c => ({
|
|
79
88
|
path: c.path,
|
|
@@ -100,6 +109,10 @@ export function AICollectionGeneratorPopover({
|
|
|
100
109
|
onGenerated(result.collection, result.operations);
|
|
101
110
|
setMenuOpen(false);
|
|
102
111
|
setPrompt("");
|
|
112
|
+
onAnalyticsEvent?.("ai_collection_generate_success", {
|
|
113
|
+
mode,
|
|
114
|
+
operationsCount: result.operations?.length
|
|
115
|
+
});
|
|
103
116
|
snackbarController.open({
|
|
104
117
|
type: "success",
|
|
105
118
|
message: existingCollection
|
|
@@ -112,6 +125,10 @@ export function AICollectionGeneratorPopover({
|
|
|
112
125
|
? e.message
|
|
113
126
|
: "Failed to generate collection. Please try again.";
|
|
114
127
|
setError(errorMessage);
|
|
128
|
+
onAnalyticsEvent?.("ai_collection_generate_error", {
|
|
129
|
+
mode,
|
|
130
|
+
error: errorMessage
|
|
131
|
+
});
|
|
115
132
|
snackbarController.open({
|
|
116
133
|
type: "error",
|
|
117
134
|
message: errorMessage
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
Container,
|
|
9
9
|
DebouncedTextField,
|
|
10
10
|
Dialog,
|
|
11
|
+
HistoryIcon,
|
|
11
12
|
IconButton,
|
|
12
13
|
Select,
|
|
13
14
|
SelectItem,
|
|
@@ -375,9 +376,9 @@ export function CollectionDetailsForm({
|
|
|
375
376
|
position={"start"}
|
|
376
377
|
size={"large"}
|
|
377
378
|
allowIndeterminate={true}
|
|
378
|
-
label={values.history === null || values.history === undefined ? "Document history revisions enabled if enabled globally" : (
|
|
379
|
+
label={<span className="flex items-center gap-2"><HistoryIcon size={"smallest"} />{values.history === null || values.history === undefined ? "Document history revisions enabled if enabled globally" : (
|
|
379
380
|
values.history ? "Document history revisions ENABLED" : "Document history revisions NOT enabled"
|
|
380
|
-
)}
|
|
381
|
+
)}</span>}
|
|
381
382
|
onValueChange={(v) => setFieldValue("history", v)}
|
|
382
383
|
value={values.history === undefined ? null : values.history}
|
|
383
384
|
/>
|
|
@@ -106,6 +106,10 @@ export interface CollectionEditorDialogProps {
|
|
|
106
106
|
* The plugin is API-agnostic - the consumer provides the implementation.
|
|
107
107
|
*/
|
|
108
108
|
generateCollection?: CollectionGenerationCallback;
|
|
109
|
+
/**
|
|
110
|
+
* Optional analytics callback
|
|
111
|
+
*/
|
|
112
|
+
onAnalyticsEvent?: (event: string, params?: object) => void;
|
|
109
113
|
}
|
|
110
114
|
|
|
111
115
|
export function CollectionEditorDialog(props: CollectionEditorDialogProps) {
|
|
@@ -290,7 +294,8 @@ function CollectionEditorInternal<M extends Record<string, any>>({
|
|
|
290
294
|
existingEntities,
|
|
291
295
|
initialView: initialViewProp,
|
|
292
296
|
expandKanban,
|
|
293
|
-
generateCollection
|
|
297
|
+
generateCollection,
|
|
298
|
+
onAnalyticsEvent
|
|
294
299
|
}: CollectionEditorDialogProps & {
|
|
295
300
|
handleCancel: () => void,
|
|
296
301
|
setFormDirty: (dirty: boolean) => void,
|
|
@@ -630,6 +635,7 @@ function CollectionEditorInternal<M extends Record<string, any>>({
|
|
|
630
635
|
existingCollection={values}
|
|
631
636
|
onGenerated={handleAIGenerated}
|
|
632
637
|
generateCollection={generateCollection}
|
|
638
|
+
onAnalyticsEvent={onAnalyticsEvent}
|
|
633
639
|
/>
|
|
634
640
|
)}
|
|
635
641
|
<Tabs value={currentView}
|
|
@@ -669,7 +675,8 @@ function CollectionEditorInternal<M extends Record<string, any>>({
|
|
|
669
675
|
onContinue={onWelcomeScreenContinue}
|
|
670
676
|
existingCollectionPaths={existingPaths}
|
|
671
677
|
parentCollection={parentCollection}
|
|
672
|
-
generateCollection={generateCollection}
|
|
678
|
+
generateCollection={generateCollection}
|
|
679
|
+
onAnalyticsEvent={onAnalyticsEvent} />}
|
|
673
680
|
|
|
674
681
|
{currentView === "import_data_mapping" && importConfig &&
|
|
675
682
|
<CollectionEditorImportMapping importConfig={importConfig}
|
|
@@ -867,7 +874,9 @@ function applyPropertyConfigs<M extends Record<string, any> = any>(collection: P
|
|
|
867
874
|
const propertiesResult: PropertiesOrBuilders<any> = {};
|
|
868
875
|
if (properties) {
|
|
869
876
|
Object.keys(properties).forEach((key) => {
|
|
870
|
-
|
|
877
|
+
const prop = properties[key];
|
|
878
|
+
if (prop == null) return;
|
|
879
|
+
propertiesResult[key] = applyPropertiesConfig(prop as PropertyOrBuilder, propertyConfigs);
|
|
871
880
|
});
|
|
872
881
|
}
|
|
873
882
|
|
|
@@ -879,7 +888,7 @@ function applyPropertyConfigs<M extends Record<string, any> = any>(collection: P
|
|
|
879
888
|
|
|
880
889
|
function applyPropertiesConfig(property: PropertyOrBuilder, propertyConfigs: Record<string, PropertyConfig<any>>) {
|
|
881
890
|
let internalProperty = property;
|
|
882
|
-
if (propertyConfigs && typeof internalProperty === "object" && internalProperty.propertyConfig) {
|
|
891
|
+
if (propertyConfigs && internalProperty && typeof internalProperty === "object" && internalProperty.propertyConfig) {
|
|
883
892
|
const propertyConfig = propertyConfigs[internalProperty.propertyConfig];
|
|
884
893
|
if (propertyConfig && isPropertyBuilder(propertyConfig.property)) {
|
|
885
894
|
internalProperty = propertyConfig.property;
|
|
@@ -18,13 +18,15 @@ export function CollectionEditorWelcomeView({
|
|
|
18
18
|
parentCollection,
|
|
19
19
|
onContinue,
|
|
20
20
|
existingCollectionPaths,
|
|
21
|
-
generateCollection
|
|
21
|
+
generateCollection,
|
|
22
|
+
onAnalyticsEvent
|
|
22
23
|
}: {
|
|
23
24
|
path: string;
|
|
24
25
|
parentCollection?: EntityCollection;
|
|
25
26
|
onContinue: (importData?: object[], propertiesOrder?: string[]) => void;
|
|
26
27
|
existingCollectionPaths?: string[];
|
|
27
28
|
generateCollection?: CollectionGenerationCallback;
|
|
29
|
+
onAnalyticsEvent?: (event: string, params?: object) => void;
|
|
28
30
|
}) {
|
|
29
31
|
|
|
30
32
|
const { pathSuggestions } = useCollectionEditorController();
|
|
@@ -99,6 +101,7 @@ export function CollectionEditorWelcomeView({
|
|
|
99
101
|
onContinue();
|
|
100
102
|
}}
|
|
101
103
|
generateCollection={generateCollection}
|
|
104
|
+
onAnalyticsEvent={onAnalyticsEvent}
|
|
102
105
|
trigger={
|
|
103
106
|
<Button
|
|
104
107
|
variant="outlined"
|
|
@@ -17,7 +17,9 @@ import {
|
|
|
17
17
|
DebouncedTextField,
|
|
18
18
|
Dialog,
|
|
19
19
|
ExpandablePanel,
|
|
20
|
+
HistoryIcon,
|
|
20
21
|
IconButton,
|
|
22
|
+
SearchIcon,
|
|
21
23
|
Select,
|
|
22
24
|
SelectItem,
|
|
23
25
|
TextField,
|
|
@@ -179,10 +181,10 @@ export function GeneralSettingsForm({
|
|
|
179
181
|
{/* Collection ID */}
|
|
180
182
|
<div className={"col-span-12"}>
|
|
181
183
|
<Field name={"id"}
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
184
|
+
as={DebouncedTextField}
|
|
185
|
+
disabled={!isNewCollection}
|
|
186
|
+
label={"Collection ID"}
|
|
187
|
+
error={showErrors && Boolean(errors.id)} />
|
|
186
188
|
<FieldCaption error={touched.id && Boolean(errors.id)}>
|
|
187
189
|
{touched.id && Boolean(errors.id) ? errors.id : "This ID identifies this collection. Typically the same as the path."}
|
|
188
190
|
</FieldCaption>
|
|
@@ -218,9 +220,9 @@ export function GeneralSettingsForm({
|
|
|
218
220
|
position={"start"}
|
|
219
221
|
size={"large"}
|
|
220
222
|
allowIndeterminate={true}
|
|
221
|
-
label={values.history === null || values.history === undefined ? "Document history revisions enabled if enabled globally" : (
|
|
223
|
+
label={<span className="flex items-center gap-2"><HistoryIcon size={"smallest"} />{values.history === null || values.history === undefined ? "Document history revisions enabled if enabled globally" : (
|
|
222
224
|
values.history ? "Document history revisions ENABLED" : "Document history revisions NOT enabled"
|
|
223
|
-
)}
|
|
225
|
+
)}</span>}
|
|
224
226
|
onValueChange={(v) => setFieldValue("history", v)}
|
|
225
227
|
value={values.history === undefined ? null : values.history}
|
|
226
228
|
/>
|
|
@@ -283,7 +285,7 @@ export function GeneralSettingsForm({
|
|
|
283
285
|
<BooleanSwitchWithLabel
|
|
284
286
|
position={"start"}
|
|
285
287
|
size={"large"}
|
|
286
|
-
label="Enable text search for this collection
|
|
288
|
+
label={<span className="flex items-center gap-2"><SearchIcon size={"smallest"} />Enable text search for this collection</span>}
|
|
287
289
|
onValueChange={(v) => setFieldValue("textSearchEnabled", v)}
|
|
288
290
|
value={values.textSearchEnabled ?? false}
|
|
289
291
|
/>
|
|
@@ -313,7 +313,7 @@ export function PropertyFormDialog({
|
|
|
313
313
|
onOkClicked?: () => void;
|
|
314
314
|
onCancel?: () => void;
|
|
315
315
|
}) {
|
|
316
|
-
const formexRef = useRef<FormexController<PropertyWithId>>();
|
|
316
|
+
const formexRef = useRef<FormexController<PropertyWithId>>(undefined);
|
|
317
317
|
const getController = (helpers: FormexController<PropertyWithId>) => {
|
|
318
318
|
formexRef.current = helpers;
|
|
319
319
|
};
|