@firecms/core 3.0.0-beta.12 → 3.0.0-beta.14
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/app/Scaffold.d.ts +4 -0
- package/dist/components/ArrayContainer.d.ts +13 -11
- package/dist/components/EntityCollectionView/EntityCollectionView.d.ts +4 -0
- package/dist/components/EntityJsonPreview.d.ts +3 -0
- package/dist/components/EntityPreview.d.ts +4 -2
- package/dist/components/SelectableTable/SelectableTable.d.ts +1 -1
- package/dist/components/VirtualTable/VirtualTableProps.d.ts +0 -4
- package/dist/components/index.d.ts +1 -0
- package/dist/core/DefaultAppBar.d.ts +8 -2
- package/dist/core/EntityEditView.d.ts +8 -1
- package/dist/core/FireCMS.d.ts +2 -2
- package/dist/form/EntityForm.d.ts +5 -1
- package/dist/form/PropertyFieldBinding.d.ts +1 -1
- package/dist/form/field_bindings/MapFieldBinding.d.ts +1 -1
- package/dist/form/field_bindings/StorageUploadFieldBinding.d.ts +3 -9
- package/dist/hooks/data/save.d.ts +1 -1
- package/dist/hooks/useBuildNavigationController.d.ts +2 -9
- package/dist/index.es.js +9251 -8721
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +16686 -16160
- package/dist/index.umd.js.map +1 -1
- package/dist/internal/useBuildDataSource.d.ts +3 -2
- package/dist/internal/useBuildSideEntityController.d.ts +3 -3
- package/dist/types/collections.d.ts +26 -2
- package/dist/types/fields.d.ts +4 -1
- package/dist/types/firecms.d.ts +3 -2
- package/dist/types/navigation.d.ts +9 -0
- package/dist/types/plugins.d.ts +13 -0
- package/dist/types/properties.d.ts +22 -1
- package/dist/types/side_entity_controller.d.ts +4 -0
- package/dist/util/callbacks.d.ts +2 -0
- package/dist/util/createFormexStub.d.ts +2 -0
- package/dist/util/index.d.ts +1 -0
- package/dist/util/navigation_utils.d.ts +2 -1
- package/dist/util/objects.d.ts +1 -1
- package/dist/util/property_utils.d.ts +2 -2
- package/dist/util/references.d.ts +2 -2
- package/dist/util/resolutions.d.ts +11 -6
- package/package.json +9 -6
- package/src/app/Scaffold.tsx +13 -3
- package/src/components/ArrayContainer.tsx +414 -282
- package/src/components/ClearFilterSortButton.tsx +1 -1
- package/src/components/ConfirmationDialog.tsx +9 -9
- package/src/components/DeleteEntityDialog.tsx +4 -2
- package/src/components/EntityCollectionTable/EntityCollectionRowActions.tsx +8 -6
- package/src/components/EntityCollectionTable/PropertyTableCell.tsx +1 -1
- package/src/components/EntityCollectionTable/internal/CollectionTableToolbar.tsx +1 -1
- package/src/components/EntityCollectionTable/internal/EntityTableCell.tsx +13 -2
- package/src/components/EntityCollectionTable/internal/popup_field/PopupFormField.tsx +58 -29
- package/src/components/EntityCollectionTable/internal/popup_field/useDraggable.tsx +9 -9
- package/src/components/EntityCollectionView/EntityCollectionView.tsx +26 -6
- package/src/components/EntityJsonPreview.tsx +66 -0
- package/src/components/EntityPreview.tsx +27 -16
- package/src/components/EntityView.tsx +4 -1
- package/src/components/ErrorView.tsx +1 -1
- package/src/components/HomePage/DefaultHomePage.tsx +2 -1
- package/src/components/HomePage/NavigationCardBinding.tsx +3 -1
- package/src/components/ReferenceTable/ReferenceSelectionTable.tsx +3 -1
- package/src/components/SelectableTable/SelectableTable.tsx +140 -143
- package/src/components/VirtualTable/VirtualTable.tsx +37 -31
- package/src/components/VirtualTable/VirtualTableProps.tsx +0 -5
- package/src/components/VirtualTable/fields/VirtualTableInput.tsx +0 -1
- package/src/components/common/default_entity_actions.tsx +15 -4
- package/src/components/index.tsx +2 -0
- package/src/core/DefaultAppBar.tsx +17 -5
- package/src/core/EntityEditView.tsx +135 -47
- package/src/core/EntitySidePanel.tsx +15 -20
- package/src/core/FireCMS.tsx +19 -12
- package/src/form/EntityForm.tsx +32 -24
- package/src/form/PropertyFieldBinding.tsx +8 -6
- package/src/form/components/CustomIdField.tsx +3 -1
- package/src/form/components/LabelWithIcon.tsx +1 -1
- package/src/form/field_bindings/ArrayCustomShapedFieldBinding.tsx +4 -1
- package/src/form/field_bindings/ArrayOfReferencesFieldBinding.tsx +4 -2
- package/src/form/field_bindings/BlockFieldBinding.tsx +1 -1
- package/src/form/field_bindings/KeyValueFieldBinding.tsx +1 -1
- package/src/form/field_bindings/MapFieldBinding.tsx +5 -4
- package/src/form/field_bindings/MarkdownEditorFieldBinding.tsx +6 -2
- package/src/form/field_bindings/MultiSelectFieldBinding.tsx +3 -3
- package/src/form/field_bindings/RepeatFieldBinding.tsx +9 -2
- package/src/form/field_bindings/SelectFieldBinding.tsx +3 -2
- package/src/form/field_bindings/StorageUploadFieldBinding.tsx +227 -156
- package/src/hooks/data/save.ts +24 -35
- package/src/hooks/useBuildNavigationController.tsx +42 -17
- package/src/hooks/useFireCMSContext.tsx +0 -30
- package/src/internal/useBuildDataSource.ts +9 -5
- package/src/internal/useBuildSideEntityController.tsx +26 -20
- package/src/preview/PropertyPreview.tsx +4 -2
- package/src/preview/components/ImagePreview.tsx +2 -2
- package/src/preview/components/ReferencePreview.tsx +1 -1
- package/src/preview/property_previews/ArrayOfMapsPreview.tsx +5 -4
- package/src/preview/property_previews/ArrayOfReferencesPreview.tsx +4 -3
- package/src/preview/property_previews/ArrayOfStorageComponentsPreview.tsx +4 -2
- package/src/preview/property_previews/ArrayOfStringsPreview.tsx +4 -3
- package/src/preview/property_previews/ArrayOneOfPreview.tsx +4 -2
- package/src/preview/property_previews/ArrayPropertyPreview.tsx +4 -2
- package/src/preview/property_previews/MapPropertyPreview.tsx +1 -1
- package/src/preview/property_previews/SkeletonPropertyComponent.tsx +1 -1
- package/src/preview/property_previews/StringPropertyPreview.tsx +1 -1
- package/src/routes/FireCMSRoute.tsx +15 -4
- package/src/types/collections.ts +31 -2
- package/src/types/fields.tsx +5 -1
- package/src/types/firecms.tsx +3 -3
- package/src/types/navigation.ts +11 -0
- package/src/types/plugins.tsx +17 -0
- package/src/types/properties.ts +27 -1
- package/src/types/side_entity_controller.tsx +5 -0
- package/src/util/callbacks.ts +119 -0
- package/src/util/createFormexStub.tsx +62 -0
- package/src/util/index.ts +1 -0
- package/src/util/join_collections.ts +3 -1
- package/src/util/navigation_from_path.ts +5 -1
- package/src/util/navigation_utils.ts +84 -20
- package/src/util/objects.ts +54 -17
- package/src/util/property_utils.tsx +7 -3
- package/src/util/references.ts +8 -6
- package/src/util/resolutions.ts +17 -9
- package/src/util/useStorageUploadController.tsx +21 -2
- package/dist/components/EntityCollectionTable/internal/popup_field/ElementResizeListener.d.ts +0 -5
- package/src/components/EntityCollectionTable/internal/popup_field/ElementResizeListener.tsx +0 -59
package/src/form/EntityForm.tsx
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React, { useCallback, useDeferredValue, useEffect, useMemo, useRef, useState } from "react";
|
|
2
2
|
import {
|
|
3
|
+
AuthController,
|
|
3
4
|
CMSAnalyticsEvent,
|
|
4
5
|
Entity,
|
|
5
6
|
EntityCollection,
|
|
@@ -28,6 +29,7 @@ import {
|
|
|
28
29
|
|
|
29
30
|
import {
|
|
30
31
|
saveEntityWithCallbacks,
|
|
32
|
+
useAuthController,
|
|
31
33
|
useCustomizationController,
|
|
32
34
|
useDataSource,
|
|
33
35
|
useFireCMSContext,
|
|
@@ -71,6 +73,10 @@ export type EntityFormProps<M extends Record<string, any>> = {
|
|
|
71
73
|
onEntityChange?: (entity: Entity<M>) => void;
|
|
72
74
|
formex?: FormexController<M>;
|
|
73
75
|
openEntityMode?: "side_panel" | "full_screen";
|
|
76
|
+
/**
|
|
77
|
+
* If true, the form will be disabled and no actions will be available
|
|
78
|
+
*/
|
|
79
|
+
disabled?: boolean;
|
|
74
80
|
/**
|
|
75
81
|
* Include the copy and delete actions in the form
|
|
76
82
|
*/
|
|
@@ -105,6 +111,7 @@ export function EntityForm<M extends Record<string, any>>({
|
|
|
105
111
|
onEntityChange,
|
|
106
112
|
openEntityMode = "full_screen",
|
|
107
113
|
formex: formexProp,
|
|
114
|
+
disabled: disabledProp,
|
|
108
115
|
Builder,
|
|
109
116
|
EntityFormActionsComponent = EntityFormActions,
|
|
110
117
|
showDefaultActions = true,
|
|
@@ -116,8 +123,8 @@ export function EntityForm<M extends Record<string, any>>({
|
|
|
116
123
|
console.warn(`The collection ${collection.path} has customId and formAutoSave enabled. This is not supported and formAutoSave will be ignored`);
|
|
117
124
|
}
|
|
118
125
|
|
|
126
|
+
const authController = useAuthController();
|
|
119
127
|
const [status, setStatus] = useState<EntityStatus>(initialStatus);
|
|
120
|
-
const [saving, setSaving] = useState(false);
|
|
121
128
|
|
|
122
129
|
const updateStatus = (status: EntityStatus) => {
|
|
123
130
|
setStatus(status);
|
|
@@ -204,7 +211,7 @@ export function EntityForm<M extends Record<string, any>>({
|
|
|
204
211
|
};
|
|
205
212
|
|
|
206
213
|
const formex: FormexController<M> = formexProp ?? useCreateFormex<M>({
|
|
207
|
-
initialValues: (initialDirtyValues ?? getInitialEntityValues(collection, path, status, entity, customizationController.propertyConfigs)) as M,
|
|
214
|
+
initialValues: (initialDirtyValues ?? getInitialEntityValues(authController, collection, path, status, entity, customizationController.propertyConfigs)) as M,
|
|
208
215
|
initialDirty: Boolean(initialDirtyValues),
|
|
209
216
|
onSubmit,
|
|
210
217
|
onReset: () => {
|
|
@@ -222,7 +229,6 @@ export function EntityForm<M extends Record<string, any>>({
|
|
|
222
229
|
}
|
|
223
230
|
});
|
|
224
231
|
|
|
225
|
-
|
|
226
232
|
useEffect(() => {
|
|
227
233
|
|
|
228
234
|
const handleKeyDown = (e: KeyboardEvent) => {
|
|
@@ -251,11 +257,11 @@ export function EntityForm<M extends Record<string, any>>({
|
|
|
251
257
|
entityId,
|
|
252
258
|
values: formex.values,
|
|
253
259
|
previousValues: formex.initialValues,
|
|
254
|
-
propertyConfigs: customizationController.propertyConfigs
|
|
260
|
+
propertyConfigs: customizationController.propertyConfigs,
|
|
261
|
+
authController
|
|
255
262
|
}), [collection, path, entityId, formex.values, formex.initialValues, customizationController.propertyConfigs]);
|
|
256
263
|
|
|
257
264
|
const onPreSaveHookError = useCallback((e: Error) => {
|
|
258
|
-
setSaving(false);
|
|
259
265
|
snackbarController.open({
|
|
260
266
|
type: "error",
|
|
261
267
|
message: "Error before saving: " + e?.message
|
|
@@ -264,7 +270,6 @@ export function EntityForm<M extends Record<string, any>>({
|
|
|
264
270
|
}, [snackbarController]);
|
|
265
271
|
|
|
266
272
|
const onSaveSuccessHookError = useCallback((e: Error) => {
|
|
267
|
-
setSaving(false);
|
|
268
273
|
snackbarController.open({
|
|
269
274
|
type: "error",
|
|
270
275
|
message: "Error after saving (entity is saved): " + e?.message
|
|
@@ -284,7 +289,6 @@ export function EntityForm<M extends Record<string, any>>({
|
|
|
284
289
|
|
|
285
290
|
clearDirtyCache();
|
|
286
291
|
onValuesModified?.(false);
|
|
287
|
-
setSaving(false);
|
|
288
292
|
if (!autoSave)
|
|
289
293
|
snackbarController.open({
|
|
290
294
|
type: "success",
|
|
@@ -306,7 +310,6 @@ export function EntityForm<M extends Record<string, any>>({
|
|
|
306
310
|
};
|
|
307
311
|
|
|
308
312
|
const onSaveFailure = useCallback((e: Error) => {
|
|
309
|
-
setSaving(false);
|
|
310
313
|
snackbarController.open({
|
|
311
314
|
type: "error",
|
|
312
315
|
message: "Error saving: " + e?.message
|
|
@@ -328,7 +331,6 @@ export function EntityForm<M extends Record<string, any>>({
|
|
|
328
331
|
values: M,
|
|
329
332
|
previousValues?: M,
|
|
330
333
|
}) => {
|
|
331
|
-
setSaving(true);
|
|
332
334
|
return saveEntityWithCallbacks({
|
|
333
335
|
path,
|
|
334
336
|
entityId,
|
|
@@ -338,7 +340,7 @@ export function EntityForm<M extends Record<string, any>>({
|
|
|
338
340
|
status,
|
|
339
341
|
dataSource,
|
|
340
342
|
context,
|
|
341
|
-
onSaveSuccess
|
|
343
|
+
onSaveSuccess,
|
|
342
344
|
onSaveFailure,
|
|
343
345
|
onPreSaveHookError,
|
|
344
346
|
onSaveSuccessHookError
|
|
@@ -398,6 +400,8 @@ export function EntityForm<M extends Record<string, any>>({
|
|
|
398
400
|
});
|
|
399
401
|
};
|
|
400
402
|
|
|
403
|
+
const disabled = formex.isSubmitting || Boolean(disabledProp);
|
|
404
|
+
|
|
401
405
|
const formContext: FormContext<M> = {
|
|
402
406
|
// @ts-ignore
|
|
403
407
|
setFieldValue: useCallback(formex.setFieldValue, []),
|
|
@@ -410,7 +414,8 @@ export function EntityForm<M extends Record<string, any>>({
|
|
|
410
414
|
entity,
|
|
411
415
|
savingError,
|
|
412
416
|
status,
|
|
413
|
-
openEntityMode
|
|
417
|
+
openEntityMode,
|
|
418
|
+
disabled
|
|
414
419
|
};
|
|
415
420
|
|
|
416
421
|
useEffect(() => {
|
|
@@ -427,6 +432,7 @@ export function EntityForm<M extends Record<string, any>>({
|
|
|
427
432
|
const pluginActions: React.ReactNode[] = [];
|
|
428
433
|
const plugins = customizationController.plugins;
|
|
429
434
|
|
|
435
|
+
const actionsDisabled = disabled || formex.isSubmitting || (status === "existing" && !formex.dirty) || Boolean(disabledProp);
|
|
430
436
|
if (plugins && collection) {
|
|
431
437
|
const actionProps: PluginFormActionProps = {
|
|
432
438
|
entityId,
|
|
@@ -436,7 +442,8 @@ export function EntityForm<M extends Record<string, any>>({
|
|
|
436
442
|
context,
|
|
437
443
|
currentEntityId: entityId,
|
|
438
444
|
formContext,
|
|
439
|
-
openEntityMode
|
|
445
|
+
openEntityMode,
|
|
446
|
+
disabled: actionsDisabled,
|
|
440
447
|
};
|
|
441
448
|
pluginActions.push(...plugins.map((plugin) => (
|
|
442
449
|
plugin.form?.Actions
|
|
@@ -544,7 +551,7 @@ export function EntityForm<M extends Record<string, any>>({
|
|
|
544
551
|
!!underlyingChanges &&
|
|
545
552
|
Object.keys(underlyingChanges).includes(key) &&
|
|
546
553
|
formex.touched[key];
|
|
547
|
-
const disabled = (!autoSave && formex.isSubmitting) || isReadOnly(property) || Boolean(property.disabled);
|
|
554
|
+
const disabled = disabledProp || (!autoSave && formex.isSubmitting) || isReadOnly(property) || Boolean(property.disabled);
|
|
548
555
|
const hidden = isHidden(property);
|
|
549
556
|
if (hidden) return null;
|
|
550
557
|
const widthPercentage = property.widthPercentage ?? 100;
|
|
@@ -614,7 +621,7 @@ export function EntityForm<M extends Record<string, any>>({
|
|
|
614
621
|
<>
|
|
615
622
|
{!Builder && <div className={"w-full py-2 flex flex-col items-start my-4 lg:my-6"}>
|
|
616
623
|
<Typography
|
|
617
|
-
className={"
|
|
624
|
+
className={"my-4 flex-grow line-clamp-1 " + (collection.hideIdFromForm ? "mb-6" : "")}
|
|
618
625
|
variant={"h4"}>
|
|
619
626
|
{title ?? collection.singularName ?? collection.name}
|
|
620
627
|
</Typography>
|
|
@@ -654,8 +661,6 @@ export function EntityForm<M extends Record<string, any>>({
|
|
|
654
661
|
onIdChange(entityId);
|
|
655
662
|
}, [entityId, onIdChange]);
|
|
656
663
|
|
|
657
|
-
const disabled = formex.isSubmitting || (!formex.dirty && status === "existing");
|
|
658
|
-
|
|
659
664
|
if (!resolvedCollection || !path) {
|
|
660
665
|
throw Error("INTERNAL: Collection and path must be defined in form context");
|
|
661
666
|
}
|
|
@@ -667,7 +672,7 @@ export function EntityForm<M extends Record<string, any>>({
|
|
|
667
672
|
layout={forceActionsAtTheBottom ? "bottom" : "side"}
|
|
668
673
|
savingError={savingError}
|
|
669
674
|
formex={formex}
|
|
670
|
-
disabled={
|
|
675
|
+
disabled={actionsDisabled}
|
|
671
676
|
status={status}
|
|
672
677
|
pluginActions={pluginActions ?? []}
|
|
673
678
|
openEntityMode={openEntityMode}
|
|
@@ -675,11 +680,11 @@ export function EntityForm<M extends Record<string, any>>({
|
|
|
675
680
|
/>;
|
|
676
681
|
|
|
677
682
|
return (
|
|
678
|
-
<Formex value={
|
|
683
|
+
<Formex value={formex}>
|
|
679
684
|
<form
|
|
680
|
-
onSubmit={
|
|
685
|
+
onSubmit={formex.handleSubmit}
|
|
681
686
|
onReset={() => formex.resetForm({
|
|
682
|
-
values: getInitialEntityValues(collection, path, status, entity, customizationController.propertyConfigs) as M
|
|
687
|
+
values: getInitialEntityValues(authController, collection, path, status, entity, customizationController.propertyConfigs) as M
|
|
683
688
|
})}
|
|
684
689
|
noValidate
|
|
685
690
|
className={cls("flex-1 flex flex-row w-full overflow-y-auto justify-center", className)}>
|
|
@@ -689,8 +694,8 @@ export function EntityForm<M extends Record<string, any>>({
|
|
|
689
694
|
|
|
690
695
|
<div className={cls("flex flex-col w-full pt-12 pb-16 px-4 sm:px-8 md:px-10")}>
|
|
691
696
|
|
|
692
|
-
{
|
|
693
|
-
? <Tooltip title={"
|
|
697
|
+
{formex.dirty
|
|
698
|
+
? <Tooltip title={"Local unsaved changes"}
|
|
694
699
|
className={"self-end sticky top-4 z-10"}>
|
|
695
700
|
<Chip size={"small"} colorScheme={"orangeDarker"}>
|
|
696
701
|
<EditIcon size={"smallest"}/>
|
|
@@ -716,17 +721,19 @@ export function EntityForm<M extends Record<string, any>>({
|
|
|
716
721
|
}
|
|
717
722
|
|
|
718
723
|
function getInitialEntityValues<M extends object>(
|
|
724
|
+
authController: AuthController,
|
|
719
725
|
collection: EntityCollection,
|
|
720
726
|
path: string,
|
|
721
727
|
status: "new" | "existing" | "copy",
|
|
722
728
|
entity: Entity<M> | undefined,
|
|
723
|
-
propertyConfigs?: Record<string, PropertyConfig
|
|
729
|
+
propertyConfigs?: Record<string, PropertyConfig>,
|
|
724
730
|
): Partial<EntityValues<M>> {
|
|
725
731
|
const resolvedCollection = resolveCollection({
|
|
726
732
|
collection,
|
|
727
733
|
path,
|
|
728
734
|
values: entity?.values,
|
|
729
|
-
propertyConfigs
|
|
735
|
+
propertyConfigs,
|
|
736
|
+
authController
|
|
730
737
|
});
|
|
731
738
|
const properties = resolvedCollection.properties;
|
|
732
739
|
if ((status === "existing" || status === "copy") && entity) {
|
|
@@ -772,3 +779,4 @@ function useOnAutoSave(autoSave: undefined | boolean, formex: FormexController<a
|
|
|
772
779
|
}
|
|
773
780
|
}, [formex.values]);
|
|
774
781
|
}
|
|
782
|
+
|
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
import { ReadOnlyFieldBinding } from "./field_bindings/ReadOnlyFieldBinding";
|
|
18
18
|
|
|
19
19
|
import { isHidden, isPropertyBuilder, isReadOnly, resolveProperty } from "../util";
|
|
20
|
-
import { useCustomizationController } from "../hooks";
|
|
20
|
+
import { useAuthController, useCustomizationController } from "../hooks";
|
|
21
21
|
import { Typography } from "@firecms/ui";
|
|
22
22
|
import { getFieldConfig, getFieldId } from "../core";
|
|
23
23
|
import { ErrorBoundary } from "../components";
|
|
@@ -87,9 +87,10 @@ function PropertyFieldBindingInternal<T extends CMSType = CMSType, M extends Rec
|
|
|
87
87
|
autoFocus,
|
|
88
88
|
index,
|
|
89
89
|
size,
|
|
90
|
-
onPropertyChange
|
|
90
|
+
onPropertyChange,
|
|
91
91
|
}: PropertyFieldBindingProps<T, M>): ReactElement<PropertyFieldBindingProps<T, M>> {
|
|
92
92
|
|
|
93
|
+
const authController = useAuthController();
|
|
93
94
|
const customizationController = useCustomizationController();
|
|
94
95
|
|
|
95
96
|
return (
|
|
@@ -107,10 +108,11 @@ function PropertyFieldBindingInternal<T extends CMSType = CMSType, M extends Rec
|
|
|
107
108
|
path: context.path,
|
|
108
109
|
entityId: context.entityId,
|
|
109
110
|
propertyConfigs: customizationController.propertyConfigs,
|
|
110
|
-
index
|
|
111
|
+
index,
|
|
112
|
+
authController
|
|
111
113
|
});
|
|
112
114
|
|
|
113
|
-
const disabled = disabledProp || isReadOnly(resolvedProperty) || Boolean(resolvedProperty?.disabled);
|
|
115
|
+
const disabled = disabledProp || isReadOnly(resolvedProperty) || Boolean(resolvedProperty?.disabled) || context.disabled;
|
|
114
116
|
|
|
115
117
|
if (resolvedProperty === null || isHidden(resolvedProperty)) {
|
|
116
118
|
return <></>;
|
|
@@ -139,7 +141,8 @@ function PropertyFieldBindingInternal<T extends CMSType = CMSType, M extends Rec
|
|
|
139
141
|
path: context.path,
|
|
140
142
|
entityId: context.entityId,
|
|
141
143
|
propertyConfigs: customizationController.propertyConfigs,
|
|
142
|
-
index
|
|
144
|
+
index,
|
|
145
|
+
authController
|
|
143
146
|
});
|
|
144
147
|
Component = configProperty.Field as ComponentType<FieldProps<T>>;
|
|
145
148
|
}
|
|
@@ -211,7 +214,6 @@ function FieldInternal<T extends CMSType, CustomProps, M extends Record<string,
|
|
|
211
214
|
|
|
212
215
|
const customFieldProps: any = property.customProps;
|
|
213
216
|
const value = formexFieldProps.field.value;
|
|
214
|
-
// const initialValue = formexFieldProps.meta.initialValue;
|
|
215
217
|
const error = getIn(formexFieldProps.form.errors, propertyKey);
|
|
216
218
|
const touched = getIn(formexFieldProps.form.touched, propertyKey);
|
|
217
219
|
|
|
@@ -103,7 +103,9 @@ export function CustomIdField<M extends Record<string, any>>({
|
|
|
103
103
|
size={"large"}
|
|
104
104
|
error={error}
|
|
105
105
|
fullWidth={true}
|
|
106
|
-
onValueChange={(v) =>
|
|
106
|
+
onValueChange={(v) => {
|
|
107
|
+
onChange(v as string);
|
|
108
|
+
}}
|
|
107
109
|
{...fieldProps}
|
|
108
110
|
renderValue={(option) => {
|
|
109
111
|
const enumConfig = enumValues.find(e => e.id === option);
|
|
@@ -24,7 +24,7 @@ export const LabelWithIcon = forwardRef<HTMLDivElement, LabelWithIconProps>(
|
|
|
24
24
|
return (
|
|
25
25
|
<div
|
|
26
26
|
ref={ref}
|
|
27
|
-
className={cls("inline-flex items-center my-0.5",
|
|
27
|
+
className={cls("align-middle inline-flex items-center my-0.5",
|
|
28
28
|
small ? "gap-1" : "gap-2",
|
|
29
29
|
className)}
|
|
30
30
|
>
|
|
@@ -5,6 +5,7 @@ import { PropertyFieldBinding } from "../PropertyFieldBinding";
|
|
|
5
5
|
import { ExpandablePanel, Typography } from "@firecms/ui";
|
|
6
6
|
import { getArrayResolvedProperties, getIconForProperty, isReadOnly } from "../../util";
|
|
7
7
|
import { useClearRestoreValue } from "../useClearRestoreValue";
|
|
8
|
+
import { useAuthController } from "../../hooks";
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* Array field used for custom
|
|
@@ -27,6 +28,7 @@ export function ArrayCustomShapedFieldBinding<T extends Array<any>>({
|
|
|
27
28
|
disabled
|
|
28
29
|
}: FieldProps<T, any, any>) {
|
|
29
30
|
|
|
31
|
+
const authController = useAuthController();
|
|
30
32
|
const minimalistView = minimalistViewProp || property.minimalistView;
|
|
31
33
|
|
|
32
34
|
let resolvedProperties = "resolvedProperties" in property ? property.resolvedProperties : undefined;
|
|
@@ -35,7 +37,8 @@ export function ArrayCustomShapedFieldBinding<T extends Array<any>>({
|
|
|
35
37
|
propertyValue: value,
|
|
36
38
|
propertyKey,
|
|
37
39
|
property,
|
|
38
|
-
ignoreMissingFields: false
|
|
40
|
+
ignoreMissingFields: false,
|
|
41
|
+
authController
|
|
39
42
|
})
|
|
40
43
|
}
|
|
41
44
|
|
|
@@ -6,7 +6,7 @@ import { ArrayContainer, ArrayEntryParams, ErrorView } from "../../components";
|
|
|
6
6
|
import { getIconForProperty, getReferenceFrom } from "../../util";
|
|
7
7
|
|
|
8
8
|
import { useNavigationController, useReferenceDialog } from "../../hooks";
|
|
9
|
-
import { Button, cls, ExpandablePanel, fieldBackgroundMixin, Typography } from "@firecms/ui";
|
|
9
|
+
import { Button, cls, EditIcon, ExpandablePanel, fieldBackgroundMixin, Typography } from "@firecms/ui";
|
|
10
10
|
import { useClearRestoreValue } from "../useClearRestoreValue";
|
|
11
11
|
|
|
12
12
|
type ArrayOfReferencesFieldProps = FieldProps<EntityReference[]>;
|
|
@@ -120,17 +120,19 @@ export function ArrayOfReferencesFieldBinding({
|
|
|
120
120
|
value={value}
|
|
121
121
|
disabled={isSubmitting}
|
|
122
122
|
buildEntry={buildEntry}
|
|
123
|
+
canAddElements={false}
|
|
123
124
|
addLabel={property.name ? "Add reference to " + property.name : "Add reference"}
|
|
124
125
|
newDefaultEntry={property.of.defaultValue}
|
|
125
126
|
onValueChange={(value) => setFieldValue(propertyKey, value)}
|
|
126
127
|
/>
|
|
127
128
|
|
|
128
129
|
<Button
|
|
129
|
-
className="my-4 justify-center text-left"
|
|
130
|
+
className="ml-3.5 my-4 justify-center text-left"
|
|
130
131
|
variant="text"
|
|
131
132
|
color="primary"
|
|
132
133
|
disabled={isSubmitting}
|
|
133
134
|
onClick={onEntryClick}>
|
|
135
|
+
<EditIcon size={"small"}/>
|
|
134
136
|
Edit {property.name}
|
|
135
137
|
</Button>
|
|
136
138
|
</div>}
|
|
@@ -88,7 +88,7 @@ export function BlockFieldBinding<T extends Array<any>>({
|
|
|
88
88
|
buildEntry={buildEntry}
|
|
89
89
|
onInternalIdAdded={setLastAddedId}
|
|
90
90
|
disabled={isSubmitting || Boolean(property.disabled)}
|
|
91
|
-
|
|
91
|
+
canAddElements={!property.disabled}
|
|
92
92
|
onValueChange={(value) => setFieldValue(propertyKey, value)}
|
|
93
93
|
newDefaultEntry={{
|
|
94
94
|
[property.oneOf!.typeField ?? DEFAULT_ONE_OF_TYPE]: firstOneOfKey,
|
|
@@ -329,7 +329,7 @@ function MapKeyValueRow<T extends Record<string, any>>({
|
|
|
329
329
|
addLabel={fieldKey ? `Add to ${fieldKey}` : "Add"}
|
|
330
330
|
size={"small"}
|
|
331
331
|
disabled={disabled || !fieldKey}
|
|
332
|
-
|
|
332
|
+
canAddElements={true}
|
|
333
333
|
onValueChange={(newValue) => {
|
|
334
334
|
setValue({
|
|
335
335
|
...value,
|
|
@@ -21,6 +21,7 @@ export function MapFieldBinding({
|
|
|
21
21
|
error,
|
|
22
22
|
disabled,
|
|
23
23
|
property,
|
|
24
|
+
partOfArray,
|
|
24
25
|
minimalistView: minimalistViewProp,
|
|
25
26
|
includeDescription,
|
|
26
27
|
autoFocus,
|
|
@@ -51,7 +52,8 @@ export function MapFieldBinding({
|
|
|
51
52
|
}
|
|
52
53
|
|
|
53
54
|
const mapFormView = <>
|
|
54
|
-
<div
|
|
55
|
+
<div
|
|
56
|
+
className={cls("py-1 flex flex-col space-y-2", minimalistView && property.widthPercentage !== undefined ? "mt-8" : undefined)}>
|
|
55
57
|
{Object.entries(mapProperties)
|
|
56
58
|
.filter(([_, property]) => !isHidden(property))
|
|
57
59
|
.map(([entryKey, childProperty], index) => {
|
|
@@ -81,8 +83,7 @@ export function MapFieldBinding({
|
|
|
81
83
|
{...fieldBindingProps}/>
|
|
82
84
|
</ErrorBoundary>
|
|
83
85
|
</div>
|
|
84
|
-
)
|
|
85
|
-
;
|
|
86
|
+
) ;
|
|
86
87
|
}
|
|
87
88
|
)
|
|
88
89
|
}
|
|
@@ -117,7 +118,7 @@ export function MapFieldBinding({
|
|
|
117
118
|
|
|
118
119
|
<FieldHelperText includeDescription={includeDescription}
|
|
119
120
|
showError={showError ?? false}
|
|
120
|
-
error={error ? (typeof error === "string" ? error : "A property of this map has an error") : undefined}
|
|
121
|
+
error={error && !partOfArray ? (typeof error === "string" ? error : "A property of this map has an error") : undefined}
|
|
121
122
|
disabled={disabled}
|
|
122
123
|
property={property}/>
|
|
123
124
|
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
randomString,
|
|
9
9
|
ResolvedArrayProperty,
|
|
10
10
|
ResolvedStringProperty,
|
|
11
|
+
useAuthController,
|
|
11
12
|
useStorageSource
|
|
12
13
|
} from "../../index";
|
|
13
14
|
import { cls, fieldBackgroundDisabledMixin, fieldBackgroundHoverMixin, fieldBackgroundMixin } from "@firecms/ui";
|
|
@@ -34,6 +35,7 @@ export function MarkdownEditorFieldBinding({
|
|
|
34
35
|
customProps,
|
|
35
36
|
}: FieldProps<string, MarkdownEditorFieldProps>) {
|
|
36
37
|
|
|
38
|
+
const authController = useAuthController();
|
|
37
39
|
const disabled = disabledProp || isSubmitting;
|
|
38
40
|
const highlight = customProps?.highlight;
|
|
39
41
|
const editorProps = customProps?.editorProps;
|
|
@@ -62,7 +64,8 @@ export function MarkdownEditorFieldBinding({
|
|
|
62
64
|
|
|
63
65
|
const resolvedProperty = resolveProperty({
|
|
64
66
|
propertyOrBuilder: property as PropertyOrBuilder,
|
|
65
|
-
values: entityValues
|
|
67
|
+
values: entityValues,
|
|
68
|
+
authController
|
|
66
69
|
}) as ResolvedStringProperty | ResolvedArrayProperty<string[]>;
|
|
67
70
|
|
|
68
71
|
const fileNameBuilder = useCallback(async (file: File) => {
|
|
@@ -89,7 +92,8 @@ export function MarkdownEditorFieldBinding({
|
|
|
89
92
|
if (!storage) return "/";
|
|
90
93
|
const resolvedProperty = resolveProperty({
|
|
91
94
|
propertyOrBuilder: property,
|
|
92
|
-
values: entityValues
|
|
95
|
+
values: entityValues,
|
|
96
|
+
authController
|
|
93
97
|
}) as ResolvedStringProperty | ResolvedArrayProperty<string[]>;
|
|
94
98
|
return resolveStoragePathString({
|
|
95
99
|
input: storage.storagePath,
|
|
@@ -23,7 +23,7 @@ export function MultiSelectFieldBinding({
|
|
|
23
23
|
disabled,
|
|
24
24
|
property,
|
|
25
25
|
includeDescription,
|
|
26
|
-
size = "
|
|
26
|
+
size = "large",
|
|
27
27
|
autoFocus
|
|
28
28
|
}: FieldProps<EnumType[], any, any>) {
|
|
29
29
|
|
|
@@ -83,8 +83,8 @@ export function MultiSelectFieldBinding({
|
|
|
83
83
|
<>
|
|
84
84
|
<MultiSelect
|
|
85
85
|
className={"w-full mt-2"}
|
|
86
|
-
size={size
|
|
87
|
-
value={validValue ? value.map((v) => v
|
|
86
|
+
size={size}
|
|
87
|
+
value={validValue ? value.map((v) => v?.toString()) : []}
|
|
88
88
|
disabled={disabled}
|
|
89
89
|
modalPopover={true}
|
|
90
90
|
label={<LabelWithIconAndTooltip
|
|
@@ -6,6 +6,7 @@ import { getArrayResolvedProperties, getDefaultValueFor, getIconForProperty, mer
|
|
|
6
6
|
import { PropertyFieldBinding } from "../PropertyFieldBinding";
|
|
7
7
|
import { ExpandablePanel, Typography } from "@firecms/ui";
|
|
8
8
|
import { useClearRestoreValue } from "../useClearRestoreValue";
|
|
9
|
+
import { useAuthController } from "../../hooks";
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* Generic array field that allows reordering and renders the child property
|
|
@@ -31,6 +32,7 @@ export function RepeatFieldBinding<T extends Array<any>>({
|
|
|
31
32
|
disabled
|
|
32
33
|
}: FieldProps<T>) {
|
|
33
34
|
|
|
35
|
+
const authController = useAuthController();
|
|
34
36
|
const minimalistView = minimalistViewProp || property.minimalistView;
|
|
35
37
|
|
|
36
38
|
if (!property.of)
|
|
@@ -42,7 +44,8 @@ export function RepeatFieldBinding<T extends Array<any>>({
|
|
|
42
44
|
propertyValue: value,
|
|
43
45
|
propertyKey,
|
|
44
46
|
property,
|
|
45
|
-
ignoreMissingFields: false
|
|
47
|
+
ignoreMissingFields: false,
|
|
48
|
+
authController
|
|
46
49
|
})
|
|
47
50
|
}
|
|
48
51
|
|
|
@@ -76,18 +79,22 @@ export function RepeatFieldBinding<T extends Array<any>>({
|
|
|
76
79
|
minimalistView: false,
|
|
77
80
|
autoFocus: internalId === lastAddedId,
|
|
78
81
|
};
|
|
82
|
+
console.debug("Building entry for", index, fieldProps);
|
|
79
83
|
return <ErrorBoundary>
|
|
80
84
|
<PropertyFieldBinding {...fieldProps} index={index}/>
|
|
81
85
|
</ErrorBoundary>;
|
|
82
86
|
};
|
|
83
87
|
|
|
88
|
+
const canAddElements = !property.disabled && !isSubmitting && !disabled && (property.canAddElements || property.canAddElements === undefined);
|
|
89
|
+
const sortable = property.sortable === undefined ? true : property.sortable;
|
|
84
90
|
const arrayContainer = <ArrayContainer droppableId={propertyKey}
|
|
85
91
|
addLabel={property.name ? "Add entry to " + property.name : "Add entry"}
|
|
86
92
|
value={value}
|
|
87
93
|
buildEntry={buildEntry}
|
|
88
94
|
onInternalIdAdded={setLastAddedId}
|
|
89
95
|
disabled={isSubmitting || Boolean(property.disabled)}
|
|
90
|
-
|
|
96
|
+
canAddElements={canAddElements}
|
|
97
|
+
sortable={sortable}
|
|
91
98
|
newDefaultEntry={getDefaultValueFor(property.of)}
|
|
92
99
|
onValueChange={(value) => setFieldValue(propertyKey, value)}
|
|
93
100
|
className={property.widthPercentage !== undefined ? "mt-8" : undefined}
|
|
@@ -66,9 +66,10 @@ export function SelectFieldBinding<T extends EnumType>({
|
|
|
66
66
|
/>
|
|
67
67
|
</PropertyIdCopyTooltip>}
|
|
68
68
|
endAdornment={
|
|
69
|
-
property.clearable && <IconButton
|
|
69
|
+
property.clearable && !disabled && <IconButton
|
|
70
|
+
size="small"
|
|
70
71
|
onClick={handleClearClick}>
|
|
71
|
-
<CloseIcon/>
|
|
72
|
+
<CloseIcon size={"small"}/>
|
|
72
73
|
</IconButton>
|
|
73
74
|
}
|
|
74
75
|
onValueChange={(updatedValue: string) => {
|