@firecms/collection_editor 3.0.0-alpha.21 → 3.0.0-alpha.25
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/ConfigControllerProvider.d.ts +36 -0
- package/dist/components/CollectionViewHeaderAction.d.ts +8 -0
- package/dist/components/EditorCollectionAction.d.ts +2 -0
- package/dist/components/HomePageEditorCollectionAction.d.ts +2 -0
- package/dist/components/MissingReferenceWidget.d.ts +3 -0
- package/dist/components/NewCollectionCard.d.ts +2 -0
- package/dist/components/PropertyAddColumnComponent.d.ts +6 -0
- package/dist/components/RootCollectionSuggestions.d.ts +1 -0
- package/dist/components/collection_editor/CollectionDetailsForm.d.ts +9 -0
- package/dist/components/collection_editor/CollectionEditorDialog.d.ts +37 -0
- package/dist/components/collection_editor/CollectionEditorWelcomeView.d.ts +15 -0
- package/dist/components/collection_editor/CollectionPropertiesEditorForm.d.ts +19 -0
- package/dist/components/collection_editor/CollectionYupValidation.d.ts +11 -0
- package/dist/components/collection_editor/EntityCustomViewsSelectDialog.d.ts +4 -0
- package/dist/components/collection_editor/EnumForm.d.ts +13 -0
- package/dist/components/collection_editor/PropertyEditView.d.ts +39 -0
- package/dist/components/collection_editor/PropertyFieldPreview.d.ts +15 -0
- package/dist/components/collection_editor/PropertySelectItem.d.ts +8 -0
- package/dist/components/collection_editor/PropertyTree.d.ts +30 -0
- package/dist/components/collection_editor/SelectIcons.d.ts +6 -0
- package/dist/components/collection_editor/SubcollectionsEditTab.d.ts +12 -0
- package/dist/components/collection_editor/UnsavedChangesDialog.d.ts +9 -0
- package/dist/components/collection_editor/import/CollectionEditorImportDataPreview.d.ts +7 -0
- package/dist/components/collection_editor/import/CollectionEditorImportMapping.d.ts +6 -0
- package/dist/components/collection_editor/import/clean_import_data.d.ts +7 -0
- package/dist/components/collection_editor/properties/BlockPropertyField.d.ts +7 -0
- package/dist/components/collection_editor/properties/BooleanPropertyField.d.ts +3 -0
- package/dist/components/collection_editor/properties/CommonPropertyFields.d.ts +10 -0
- package/dist/components/collection_editor/properties/DateTimePropertyField.d.ts +3 -0
- package/dist/components/collection_editor/properties/EnumPropertyField.d.ts +8 -0
- package/dist/components/collection_editor/properties/FieldHelperView.d.ts +4 -0
- package/dist/components/collection_editor/properties/KeyValuePropertyField.d.ts +3 -0
- package/dist/components/collection_editor/properties/MapPropertyField.d.ts +7 -0
- package/dist/components/collection_editor/properties/NumberPropertyField.d.ts +3 -0
- package/dist/components/collection_editor/properties/ReferencePropertyField.d.ts +13 -0
- package/dist/components/collection_editor/properties/RepeatPropertyField.d.ts +9 -0
- package/dist/components/collection_editor/properties/StoragePropertyField.d.ts +5 -0
- package/dist/components/collection_editor/properties/StringPropertyField.d.ts +5 -0
- package/dist/components/collection_editor/properties/advanced/AdvancedPropertyValidation.d.ts +3 -0
- package/dist/components/collection_editor/properties/validation/ArrayPropertyValidation.d.ts +5 -0
- package/dist/components/collection_editor/properties/validation/GeneralPropertyValidation.d.ts +4 -0
- package/dist/components/collection_editor/properties/validation/NumberPropertyValidation.d.ts +3 -0
- package/dist/components/collection_editor/properties/validation/StringPropertyValidation.d.ts +11 -0
- package/dist/components/collection_editor/properties/validation/ValidationPanel.d.ts +2 -0
- package/dist/components/collection_editor/templates/blog_template.d.ts +10 -0
- package/dist/components/collection_editor/templates/products_template.d.ts +12 -0
- package/dist/components/collection_editor/templates/users_template.d.ts +7 -0
- package/dist/components/collection_editor/util.d.ts +4 -0
- package/dist/components/collection_editor/utils/supported_fields.d.ts +3 -0
- package/dist/components/collection_editor/utils/update_property_for_widget.d.ts +2 -0
- package/dist/components/collection_editor/utils/useTraceUpdate.d.ts +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.es.js +6754 -0
- package/dist/index.es.js.map +1 -0
- package/dist/index.umd.js +2 -0
- package/dist/index.umd.js.map +1 -0
- package/dist/types/collection_editor_controller.d.ts +33 -0
- package/dist/types/collection_inference.d.ts +2 -0
- package/dist/types/config_controller.d.ts +33 -0
- package/dist/types/config_permissions.d.ts +19 -0
- package/dist/types/persisted_collection.d.ts +6 -0
- package/dist/useCollectionEditorController.d.ts +6 -0
- package/dist/useCollectionEditorPlugin.d.ts +44 -0
- package/dist/useCollectionsConfigController.d.ts +6 -0
- package/dist/utils/arrays.d.ts +1 -0
- package/dist/utils/entities.d.ts +3 -0
- package/dist/utils/icons.d.ts +1 -0
- package/dist/utils/join_collections.d.ts +13 -0
- package/dist/utils/synonyms.d.ts +1951 -0
- package/package.json +6 -5
- package/src/ConfigControllerProvider.tsx +131 -8
- package/src/components/CollectionViewHeaderAction.tsx +38 -0
- package/src/components/MissingReferenceWidget.tsx +2 -1
- package/src/components/NewCollectionCard.tsx +2 -1
- package/src/components/PropertyAddColumnComponent.tsx +39 -0
- package/src/components/RootCollectionSuggestions.tsx +2 -1
- package/src/components/collection_editor/CollectionDetailsForm.tsx +1 -0
- package/src/components/collection_editor/CollectionEditorDialog.tsx +1 -1
- package/src/components/collection_editor/CollectionPropertiesEditorForm.tsx +3 -3
- package/src/components/collection_editor/PropertyEditView.tsx +112 -97
- package/src/components/collection_editor/SubcollectionsEditTab.tsx +14 -3
- package/src/components/collection_editor/import/CollectionEditorImportMapping.tsx +1 -1
- package/src/components/collection_editor/properties/BlockPropertyField.tsx +1 -1
- package/src/components/collection_editor/properties/CommonPropertyFields.tsx +0 -1
- package/src/components/collection_editor/properties/MapPropertyField.tsx +1 -1
- package/src/components/collection_editor/properties/RepeatPropertyField.tsx +1 -1
- package/src/index.ts +1 -0
- package/src/types/collection_editor_controller.tsx +11 -2
- package/src/types/config_controller.tsx +13 -2
- package/src/types/persisted_collection.ts +2 -1
- package/src/useCollectionEditorPlugin.tsx +22 -2
- package/src/utils/join_collections.ts +11 -48
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React, { useDeferredValue, useEffect, useRef, useState } from "react";
|
|
2
2
|
import equal from "react-fast-compare"
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import { Formik, FormikErrors, FormikProps, getIn } from "formik";
|
|
5
5
|
import {
|
|
6
6
|
Button,
|
|
7
7
|
cn,
|
|
@@ -14,10 +14,13 @@ import {
|
|
|
14
14
|
FieldConfig,
|
|
15
15
|
FieldConfigBadge,
|
|
16
16
|
FieldConfigId,
|
|
17
|
+
getFieldConfig,
|
|
17
18
|
getFieldId,
|
|
18
19
|
IconButton,
|
|
19
20
|
InfoLabel,
|
|
20
|
-
isPropertyBuilder,
|
|
21
|
+
isPropertyBuilder,
|
|
22
|
+
mergeDeep,
|
|
23
|
+
Property,
|
|
21
24
|
Select,
|
|
22
25
|
toSnakeCase,
|
|
23
26
|
Typography
|
|
@@ -52,7 +55,7 @@ export type OnPropertyChangedParams = {
|
|
|
52
55
|
|
|
53
56
|
export type PropertyFormProps = {
|
|
54
57
|
includeIdAndName?: boolean;
|
|
55
|
-
|
|
58
|
+
existingProperty: boolean;
|
|
56
59
|
autoUpdateId?: boolean;
|
|
57
60
|
autoOpenTypeSelect: boolean;
|
|
58
61
|
inArray: boolean;
|
|
@@ -76,7 +79,7 @@ export const PropertyForm = React.memo(
|
|
|
76
79
|
function PropertyForm({
|
|
77
80
|
includeIdAndName = true,
|
|
78
81
|
autoOpenTypeSelect,
|
|
79
|
-
|
|
82
|
+
existingProperty,
|
|
80
83
|
autoUpdateId,
|
|
81
84
|
inArray,
|
|
82
85
|
propertyKey,
|
|
@@ -138,7 +141,7 @@ export const PropertyForm = React.memo(
|
|
|
138
141
|
id,
|
|
139
142
|
property
|
|
140
143
|
});
|
|
141
|
-
if (!
|
|
144
|
+
if (!existingProperty)
|
|
142
145
|
helpers.resetForm({ values: initialValue });
|
|
143
146
|
}}
|
|
144
147
|
// validate={(values) => {
|
|
@@ -170,7 +173,7 @@ export const PropertyForm = React.memo(
|
|
|
170
173
|
propertyNamespace={propertyNamespace}
|
|
171
174
|
onError={onError}
|
|
172
175
|
showErrors={forceShowErrors || props.submitCount > 0}
|
|
173
|
-
existing={
|
|
176
|
+
existing={existingProperty}
|
|
174
177
|
autoUpdateId={autoUpdateId}
|
|
175
178
|
inArray={inArray}
|
|
176
179
|
autoOpenTypeSelect={autoOpenTypeSelect}
|
|
@@ -189,7 +192,7 @@ export const PropertyForm = React.memo(
|
|
|
189
192
|
a.includeIdAndName === b.includeIdAndName &&
|
|
190
193
|
a.autoOpenTypeSelect === b.autoOpenTypeSelect &&
|
|
191
194
|
a.autoUpdateId === b.autoUpdateId &&
|
|
192
|
-
a.
|
|
195
|
+
a.existingProperty === b.existingProperty
|
|
193
196
|
);
|
|
194
197
|
|
|
195
198
|
export function PropertyFormDialog({
|
|
@@ -214,38 +217,36 @@ export function PropertyFormDialog({
|
|
|
214
217
|
maxWidth={"xl"}
|
|
215
218
|
fullWidth={true}
|
|
216
219
|
>
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
<
|
|
220
|
-
|
|
221
|
-
onPropertyChanged
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
{
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
</DialogActions>
|
|
248
|
-
</Form>
|
|
220
|
+
|
|
221
|
+
<DialogContent>
|
|
222
|
+
<PropertyForm {...formProps}
|
|
223
|
+
onPropertyChanged={(params) => {
|
|
224
|
+
onPropertyChanged?.(params);
|
|
225
|
+
onOkClicked?.();
|
|
226
|
+
}}
|
|
227
|
+
onPropertyChangedImmediate={false}
|
|
228
|
+
getHelpers={getHelpers}
|
|
229
|
+
getData={getData}
|
|
230
|
+
/>
|
|
231
|
+
</DialogContent>
|
|
232
|
+
|
|
233
|
+
<DialogActions>
|
|
234
|
+
|
|
235
|
+
{onCancel && <Button
|
|
236
|
+
variant={"text"}
|
|
237
|
+
onClick={() => {
|
|
238
|
+
onCancel();
|
|
239
|
+
helpersRef.current?.resetForm();
|
|
240
|
+
}}>
|
|
241
|
+
Cancel
|
|
242
|
+
</Button>}
|
|
243
|
+
|
|
244
|
+
<Button variant="outlined"
|
|
245
|
+
color="primary"
|
|
246
|
+
onClick={() => helpersRef.current?.submitForm()}>
|
|
247
|
+
Ok
|
|
248
|
+
</Button>
|
|
249
|
+
</DialogActions>
|
|
249
250
|
</Dialog>;
|
|
250
251
|
|
|
251
252
|
}
|
|
@@ -289,10 +290,11 @@ function PropertyEditView({
|
|
|
289
290
|
customFields: Record<string, FieldConfig>;
|
|
290
291
|
} & FormikProps<PropertyWithId>) {
|
|
291
292
|
|
|
293
|
+
const [selectOpen, setSelectOpen] = useState(autoOpenTypeSelect);
|
|
292
294
|
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
|
|
293
295
|
const [selectedFieldConfigId, setSelectedFieldConfigId] = useState<string | undefined>(values?.dataType ? getFieldId(values) : undefined);
|
|
294
296
|
|
|
295
|
-
const allSupportedFields = Object.entries(
|
|
297
|
+
const allSupportedFields = Object.entries(DEFAULT_FIELD_CONFIGS).concat(Object.entries(customFields));
|
|
296
298
|
|
|
297
299
|
const displayedWidgets = inArray
|
|
298
300
|
? allSupportedFields.filter(([_, fieldConfig]) => !isPropertyBuilder(fieldConfig.property) && fieldConfig.property?.dataType !== "array")
|
|
@@ -392,10 +394,12 @@ function PropertyEditView({
|
|
|
392
394
|
childComponent = <NumberPropertyField disabled={disabled}/>;
|
|
393
395
|
} else if (selectedFieldConfigId === "group") {
|
|
394
396
|
childComponent =
|
|
395
|
-
<MapPropertyField disabled={disabled} getData={getData} allowDataInference={allowDataInference}
|
|
397
|
+
<MapPropertyField disabled={disabled} getData={getData} allowDataInference={allowDataInference}
|
|
398
|
+
customFields={customFields}/>;
|
|
396
399
|
} else if (selectedFieldConfigId === "block") {
|
|
397
400
|
childComponent =
|
|
398
|
-
<BlockPropertyField disabled={disabled} getData={getData} allowDataInference={allowDataInference}
|
|
401
|
+
<BlockPropertyField disabled={disabled} getData={getData} allowDataInference={allowDataInference}
|
|
402
|
+
customFields={customFields}/>;
|
|
399
403
|
} else if (selectedFieldConfigId === "reference") {
|
|
400
404
|
childComponent =
|
|
401
405
|
<ReferencePropertyField showErrors={showErrors}
|
|
@@ -436,62 +440,73 @@ function PropertyEditView({
|
|
|
436
440
|
</InfoLabel>}
|
|
437
441
|
|
|
438
442
|
<div className="flex mt-2 justify-between">
|
|
439
|
-
<
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
<div
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
443
|
+
<div className={"w-full flex flex-col gap-2"}>
|
|
444
|
+
<Select
|
|
445
|
+
className={"w-full"}
|
|
446
|
+
error={Boolean(selectedWidgetError)}
|
|
447
|
+
value={selectedFieldConfigId ?? ""}
|
|
448
|
+
placeholder={"Select a property widget"}
|
|
449
|
+
open={selectOpen}
|
|
450
|
+
onOpenChange={setSelectOpen}
|
|
451
|
+
position={"item-aligned"}
|
|
452
|
+
disabled={disabled}
|
|
453
|
+
renderValue={(value) => {
|
|
454
|
+
if (!value) {
|
|
455
|
+
return <em>Select a property
|
|
456
|
+
widget</em>;
|
|
457
|
+
}
|
|
458
|
+
const key = value as FieldConfigId;
|
|
459
|
+
const fieldConfig = DEFAULT_FIELD_CONFIGS[key] ?? customFields[key];
|
|
460
|
+
const baseProperty = fieldConfig.property;
|
|
461
|
+
const baseFieldConfig = baseProperty && !isPropertyBuilder(baseProperty) ? getFieldConfig(baseProperty, customFields) : undefined;
|
|
462
|
+
const optionDisabled = isPropertyBuilder(baseProperty) || (existing && baseProperty.dataType !== values?.dataType);
|
|
463
|
+
const computedFieldConfig = baseFieldConfig ? mergeDeep(baseFieldConfig, fieldConfig) : fieldConfig;
|
|
464
|
+
return <div
|
|
465
|
+
onClick={(e) => {
|
|
466
|
+
if (optionDisabled) {
|
|
467
|
+
e.stopPropagation();
|
|
468
|
+
e.preventDefault();
|
|
469
|
+
}
|
|
470
|
+
}}
|
|
471
|
+
className={cn(
|
|
472
|
+
"flex items-center",
|
|
473
|
+
optionDisabled ? "w-full pointer-events-none opacity-50" : "")}>
|
|
474
|
+
<div className={"mr-8"}>
|
|
475
|
+
<FieldConfigBadge fieldConfig={computedFieldConfig}/>
|
|
476
|
+
</div>
|
|
477
|
+
<div className={"flex flex-col items-start text-base text-left"}>
|
|
478
|
+
<div>{computedFieldConfig.name}</div>
|
|
479
|
+
<Typography variant={"caption"}
|
|
480
|
+
color={"disabled"}>
|
|
481
|
+
{optionDisabled ? "You can only switch to widgets that use the same data type" : computedFieldConfig.description}
|
|
482
|
+
</Typography>
|
|
483
|
+
</div>
|
|
475
484
|
</div>
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
485
|
+
}}
|
|
486
|
+
onValueChange={(value) => {
|
|
487
|
+
onWidgetSelectChanged(value as FieldConfigId);
|
|
488
|
+
}}>
|
|
489
|
+
{displayedWidgets.map(([key, fieldConfig]) => {
|
|
490
|
+
const baseProperty = fieldConfig.property;
|
|
491
|
+
const optionDisabled = existing && !isPropertyBuilder(baseProperty) && baseProperty.dataType !== values?.dataType;
|
|
492
|
+
return <PropertySelectItem
|
|
493
|
+
key={key}
|
|
494
|
+
value={key}
|
|
495
|
+
optionDisabled={optionDisabled}
|
|
496
|
+
fieldConfig={fieldConfig}
|
|
497
|
+
existing={existing}/>;
|
|
498
|
+
})}
|
|
499
|
+
</Select>
|
|
500
|
+
|
|
501
|
+
{selectedWidgetError &&
|
|
502
|
+
<Typography variant="caption"
|
|
503
|
+
className={"ml-3.5"}
|
|
504
|
+
color={"error"}>Required</Typography>}
|
|
505
|
+
|
|
506
|
+
{/*<Typography variant="caption" className={"ml-3.5"}>Define your own custom properties and*/}
|
|
507
|
+
{/* components</Typography>*/}
|
|
508
|
+
|
|
509
|
+
</div>
|
|
495
510
|
|
|
496
511
|
{onDelete && values?.id &&
|
|
497
512
|
<IconButton
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
EntityCollection,
|
|
9
9
|
EntityCustomView,
|
|
10
10
|
IconButton,
|
|
11
|
+
InfoLabel,
|
|
11
12
|
Paper,
|
|
12
13
|
resolveEntityView,
|
|
13
14
|
Table,
|
|
@@ -128,7 +129,7 @@ export function SubcollectionsEditTab({
|
|
|
128
129
|
Custom views
|
|
129
130
|
</Typography>
|
|
130
131
|
|
|
131
|
-
{totalEntityViews > 0 &&
|
|
132
|
+
{totalEntityViews > 0 && <>
|
|
132
133
|
<Paper className={"flex flex-col gap-4 p-2 w-full"}>
|
|
133
134
|
<Table>
|
|
134
135
|
<TableBody>
|
|
@@ -164,14 +165,23 @@ export function SubcollectionsEditTab({
|
|
|
164
165
|
{view.name}
|
|
165
166
|
</Typography>
|
|
166
167
|
<Typography variant={"caption"} className={"flex-grow"}>
|
|
167
|
-
This view is defined in code with
|
|
168
|
+
This view is defined in code with
|
|
169
|
+
key <code>{view.key}</code>
|
|
168
170
|
</Typography>
|
|
169
171
|
</TableCell>
|
|
170
172
|
</TableRow>
|
|
171
173
|
))}
|
|
172
174
|
</TableBody>
|
|
173
175
|
</Table>
|
|
174
|
-
</Paper>
|
|
176
|
+
</Paper>
|
|
177
|
+
|
|
178
|
+
</>}
|
|
179
|
+
|
|
180
|
+
{totalEntityViews === 0 &&
|
|
181
|
+
<InfoLabel>
|
|
182
|
+
COMING SOON: You can define your own custom views by uploading it with the CLI
|
|
183
|
+
</InfoLabel>
|
|
184
|
+
}
|
|
175
185
|
|
|
176
186
|
<Button
|
|
177
187
|
onClick={() => {
|
|
@@ -181,6 +191,7 @@ export function SubcollectionsEditTab({
|
|
|
181
191
|
startIcon={<AddIcon/>}>
|
|
182
192
|
Add custom entity view
|
|
183
193
|
</Button>
|
|
194
|
+
|
|
184
195
|
</div>
|
|
185
196
|
|
|
186
197
|
</div>
|
|
@@ -120,7 +120,7 @@ export function BlockPropertyField({ disabled, getData, allowDataInference, cust
|
|
|
120
120
|
propertyKey={selectedPropertyKey}
|
|
121
121
|
propertyNamespace={selectedPropertyNamespace}
|
|
122
122
|
property={selectedProperty}
|
|
123
|
-
|
|
123
|
+
existingProperty={Boolean(selectedPropertyKey)}
|
|
124
124
|
autoUpdateId={!selectedPropertyKey}
|
|
125
125
|
autoOpenTypeSelect={!selectedPropertyKey}
|
|
126
126
|
onPropertyChanged={onPropertyCreated}
|
|
@@ -142,7 +142,7 @@ export function MapPropertyField({ disabled, getData, allowDataInference, custom
|
|
|
142
142
|
propertyKey={selectedPropertyKey}
|
|
143
143
|
propertyNamespace={selectedPropertyNamespace}
|
|
144
144
|
property={selectedProperty}
|
|
145
|
-
|
|
145
|
+
existingProperty={Boolean(selectedPropertyKey)}
|
|
146
146
|
autoUpdateId={!selectedPropertyKey}
|
|
147
147
|
autoOpenTypeSelect={!selectedPropertyKey}
|
|
148
148
|
onPropertyChanged={onPropertyCreated}
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { CollectionEditorPermissionsBuilder } from "./config_permissions";
|
|
2
|
-
import { EntityCollection } from "@firecms/core";
|
|
2
|
+
import { EntityCollection, Property } from "@firecms/core";
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Controller to open the collection editor dialog.
|
|
@@ -21,7 +21,16 @@ export interface CollectionEditorController {
|
|
|
21
21
|
name?: string
|
|
22
22
|
},
|
|
23
23
|
parentPathSegments: string[],
|
|
24
|
-
parentCollection?: EntityCollection<any, any, any
|
|
24
|
+
parentCollection?: EntityCollection<any, any, any>,
|
|
25
|
+
redirect: boolean
|
|
26
|
+
}) => void;
|
|
27
|
+
|
|
28
|
+
editProperty: (props: {
|
|
29
|
+
propertyKey?: string,
|
|
30
|
+
property?: Property,
|
|
31
|
+
currentPropertiesOrder?: string[],
|
|
32
|
+
editedCollectionPath: string,
|
|
33
|
+
parentPathSegments: string[],
|
|
25
34
|
}) => void;
|
|
26
35
|
|
|
27
36
|
configPermissions: CollectionEditorPermissionsBuilder;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CMSType,
|
|
1
|
+
import { CMSType, Property } from "@firecms/core";
|
|
2
2
|
import { PersistedCollection } from "./persisted_collection";
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -11,7 +11,9 @@ export interface CollectionsConfigController {
|
|
|
11
11
|
|
|
12
12
|
collections?: PersistedCollection[];
|
|
13
13
|
|
|
14
|
-
saveCollection: <M extends { [Key: string]: CMSType }>(params:SaveCollectionParams<M>) => Promise<void>;
|
|
14
|
+
saveCollection: <M extends { [Key: string]: CMSType }>(params: SaveCollectionParams<M>) => Promise<void>;
|
|
15
|
+
|
|
16
|
+
saveProperty: (params: SavePropertyParams) => Promise<void>;
|
|
15
17
|
|
|
16
18
|
deleteCollection: (props: DeleteCollectionParams) => Promise<void>;
|
|
17
19
|
|
|
@@ -24,6 +26,15 @@ export type SaveCollectionParams<M extends Record<string, any>> = {
|
|
|
24
26
|
parentPathSegments?: string[]
|
|
25
27
|
}
|
|
26
28
|
|
|
29
|
+
export type SavePropertyParams = {
|
|
30
|
+
path: string,
|
|
31
|
+
propertyKey: string,
|
|
32
|
+
namespace?: string,
|
|
33
|
+
newPropertiesOrder?: string[],
|
|
34
|
+
property: Property,
|
|
35
|
+
parentPathSegments?: string[]
|
|
36
|
+
}
|
|
37
|
+
|
|
27
38
|
export type DeleteCollectionParams = {
|
|
28
39
|
path: string,
|
|
29
40
|
parentPathSegments?: string[]
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { EntityCollection, Properties, User } from "@firecms/core";
|
|
2
2
|
|
|
3
3
|
export type PersistedCollection<M extends Record<string, any> = any, AdditionalKey extends string = string, UserType extends User = User>
|
|
4
|
-
= Omit<EntityCollection<M, AdditionalKey, UserType>, "properties"> & {
|
|
4
|
+
= Omit<EntityCollection<M, AdditionalKey, UserType>, "properties" | "subcollections"> & {
|
|
5
5
|
properties: Properties<M>;
|
|
6
6
|
ownerId: string;
|
|
7
|
+
subcollections?: PersistedCollection<any, any>[];
|
|
7
8
|
}
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import React, { useCallback } from "react";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
EntityCollection,
|
|
4
|
+
FireCMSPlugin,
|
|
5
|
+
makePropertiesEditable,
|
|
6
|
+
makePropertiesNonEditable,
|
|
7
|
+
User
|
|
8
|
+
} from "@firecms/core";
|
|
3
9
|
import { ConfigControllerProvider } from "./ConfigControllerProvider";
|
|
4
10
|
import { CollectionEditorPermissionsBuilder } from "./types/config_permissions";
|
|
5
11
|
import { EditorCollectionAction } from "./components/EditorCollectionAction";
|
|
@@ -10,6 +16,8 @@ import { CollectionInference } from "./types/collection_inference";
|
|
|
10
16
|
import { CollectionsConfigController } from "./types/config_controller";
|
|
11
17
|
import { RootCollectionSuggestions } from "./components/RootCollectionSuggestions";
|
|
12
18
|
import { joinCollectionLists } from "./utils/join_collections";
|
|
19
|
+
import { CollectionViewHeaderAction } from "./components/CollectionViewHeaderAction";
|
|
20
|
+
import { PropertyAddColumnComponent } from "./components/PropertyAddColumnComponent";
|
|
13
21
|
|
|
14
22
|
export interface CollectionConfigControllerProps<EC extends PersistedCollection = PersistedCollection, UserType extends User = User> {
|
|
15
23
|
|
|
@@ -71,7 +79,15 @@ export function useCollectionEditorPlugin<EC extends PersistedCollection = Persi
|
|
|
71
79
|
}: CollectionConfigControllerProps<EC, UserType>): FireCMSPlugin {
|
|
72
80
|
|
|
73
81
|
const injectCollections = useCallback(
|
|
74
|
-
(collections: EntityCollection[]) =>
|
|
82
|
+
(collections: EntityCollection[]) => {
|
|
83
|
+
const markAsEditable = (c: PersistedCollection) => {
|
|
84
|
+
makePropertiesEditable(c.properties);
|
|
85
|
+
c.subcollections?.forEach(markAsEditable);
|
|
86
|
+
};
|
|
87
|
+
const editableCollections = collectionConfigController.collections ?? [];
|
|
88
|
+
editableCollections.forEach(markAsEditable);
|
|
89
|
+
return joinCollectionLists(editableCollections, collections);
|
|
90
|
+
},
|
|
75
91
|
[collectionConfigController.collections]);
|
|
76
92
|
|
|
77
93
|
return {
|
|
@@ -98,6 +114,10 @@ export function useCollectionEditorPlugin<EC extends PersistedCollection = Persi
|
|
|
98
114
|
additionalChildrenStart: <RootCollectionSuggestions/>,
|
|
99
115
|
CollectionActions: HomePageEditorCollectionAction,
|
|
100
116
|
AdditionalCards: NewCollectionCard,
|
|
117
|
+
},
|
|
118
|
+
collectionView: {
|
|
119
|
+
HeaderAction: CollectionViewHeaderAction,
|
|
120
|
+
AddColumnComponent: PropertyAddColumnComponent
|
|
101
121
|
}
|
|
102
122
|
};
|
|
103
123
|
}
|
|
@@ -1,86 +1,49 @@
|
|
|
1
1
|
import {
|
|
2
2
|
EntityCollection,
|
|
3
|
-
isPropertyBuilder,
|
|
3
|
+
isPropertyBuilder,
|
|
4
|
+
MapProperty,
|
|
4
5
|
mergeDeep,
|
|
5
6
|
PropertiesOrBuilders,
|
|
6
|
-
Property,
|
|
7
|
+
Property,
|
|
8
|
+
PropertyOrBuilder,
|
|
7
9
|
sortProperties
|
|
8
10
|
} from "@firecms/core";
|
|
9
|
-
import { PersistedCollection } from "../types/persisted_collection";
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
*
|
|
13
14
|
* @param storedCollections
|
|
14
15
|
* @param codedCollections
|
|
15
16
|
*/
|
|
16
|
-
export function joinCollectionLists(storedCollections:
|
|
17
|
-
const resolvedFetchedCollections: PersistedCollection[] = storedCollections.map(c => ({
|
|
18
|
-
...c,
|
|
19
|
-
editable: true,
|
|
20
|
-
deletable: true
|
|
21
|
-
}));
|
|
17
|
+
export function joinCollectionLists(storedCollections: EntityCollection[], codedCollections: EntityCollection[] | undefined): EntityCollection[] {
|
|
22
18
|
|
|
23
19
|
// merge collections that are in both lists
|
|
24
20
|
const updatedCollections = (codedCollections ?? [])
|
|
25
21
|
.map((codedCollection) => {
|
|
26
|
-
const storedCollection =
|
|
22
|
+
const storedCollection = storedCollections?.find((collection) => {
|
|
27
23
|
return collection.path === codedCollection.path || (collection.alias && codedCollection.alias && collection.alias === codedCollection.alias);
|
|
28
24
|
});
|
|
29
25
|
if (!storedCollection) {
|
|
30
|
-
return
|
|
31
|
-
...codedCollection,
|
|
32
|
-
properties: markPropertiesAsNonEditable(codedCollection.properties as PropertiesOrBuilders),
|
|
33
|
-
deletable: false
|
|
34
|
-
};
|
|
26
|
+
return codedCollection;
|
|
35
27
|
} else {
|
|
36
|
-
|
|
37
|
-
property.editable = true
|
|
38
|
-
});
|
|
39
|
-
const mergedCollection = mergeCollections(storedCollection, codedCollection);
|
|
40
|
-
return { ...mergedCollection, deletable: false };
|
|
28
|
+
return mergeCollection(storedCollection, codedCollection);
|
|
41
29
|
}
|
|
42
30
|
});
|
|
43
31
|
|
|
44
32
|
// fetched collections that are not in the base collections
|
|
45
|
-
const resultStoredCollections =
|
|
33
|
+
const resultStoredCollections = storedCollections
|
|
46
34
|
.filter((col) => !updatedCollections.map(c => c.path).includes(col.path) || !updatedCollections.map(c => c.alias).includes(col.alias));
|
|
47
35
|
|
|
48
36
|
return [...updatedCollections, ...resultStoredCollections];
|
|
49
37
|
}
|
|
50
38
|
|
|
51
|
-
function markPropertiesAsNonEditable(properties: PropertiesOrBuilders): PropertiesOrBuilders {
|
|
52
|
-
return Object.entries(properties).reduce((acc, [key, property]) => {
|
|
53
|
-
if (!isPropertyBuilder(property) && property.dataType === "map" && property.properties) {
|
|
54
|
-
const updated = { ...property, properties: markPropertiesAsNonEditable(property.properties as PropertiesOrBuilders) };
|
|
55
|
-
acc[key] = updated;
|
|
56
|
-
}
|
|
57
|
-
if (isPropertyBuilder(property)) {
|
|
58
|
-
acc[key] = property;
|
|
59
|
-
} else {
|
|
60
|
-
acc[key] = { ...property, editable: false };
|
|
61
|
-
}
|
|
62
|
-
return acc;
|
|
63
|
-
}, {} as PropertiesOrBuilders);
|
|
64
|
-
|
|
65
|
-
}
|
|
66
|
-
|
|
67
39
|
/**
|
|
68
40
|
*
|
|
69
41
|
* @param target
|
|
70
42
|
* @param source
|
|
71
43
|
*/
|
|
72
|
-
export function
|
|
73
|
-
const subcollectionsMerged = target.subcollections?.map((targetSubcollection) => {
|
|
74
|
-
const modifiedCollection =
|
|
75
|
-
source.subcollections?.find((sourceSubcollection) => sourceSubcollection.path === targetSubcollection.path) ??
|
|
76
|
-
source.subcollections?.find((sourceSubcollection) => sourceSubcollection.alias === targetSubcollection.alias);
|
|
44
|
+
export function mergeCollection(target: EntityCollection, source: EntityCollection): EntityCollection {
|
|
77
45
|
|
|
78
|
-
|
|
79
|
-
return targetSubcollection;
|
|
80
|
-
} else {
|
|
81
|
-
return mergeCollections(targetSubcollection, modifiedCollection);
|
|
82
|
-
}
|
|
83
|
-
});
|
|
46
|
+
const subcollectionsMerged = joinCollectionLists(target?.subcollections ?? [], source?.subcollections ?? []);
|
|
84
47
|
|
|
85
48
|
const propertiesMerged: PropertiesOrBuilders = { ...target.properties } as PropertiesOrBuilders;
|
|
86
49
|
Object.keys(source.properties).forEach((key) => {
|