@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.
Files changed (120) hide show
  1. package/dist/app/Scaffold.d.ts +4 -0
  2. package/dist/components/ArrayContainer.d.ts +13 -11
  3. package/dist/components/EntityCollectionView/EntityCollectionView.d.ts +4 -0
  4. package/dist/components/EntityJsonPreview.d.ts +3 -0
  5. package/dist/components/EntityPreview.d.ts +4 -2
  6. package/dist/components/SelectableTable/SelectableTable.d.ts +1 -1
  7. package/dist/components/VirtualTable/VirtualTableProps.d.ts +0 -4
  8. package/dist/components/index.d.ts +1 -0
  9. package/dist/core/DefaultAppBar.d.ts +8 -2
  10. package/dist/core/EntityEditView.d.ts +8 -1
  11. package/dist/core/FireCMS.d.ts +2 -2
  12. package/dist/form/EntityForm.d.ts +5 -1
  13. package/dist/form/PropertyFieldBinding.d.ts +1 -1
  14. package/dist/form/field_bindings/MapFieldBinding.d.ts +1 -1
  15. package/dist/form/field_bindings/StorageUploadFieldBinding.d.ts +3 -9
  16. package/dist/hooks/data/save.d.ts +1 -1
  17. package/dist/hooks/useBuildNavigationController.d.ts +2 -9
  18. package/dist/index.es.js +9251 -8721
  19. package/dist/index.es.js.map +1 -1
  20. package/dist/index.umd.js +16686 -16160
  21. package/dist/index.umd.js.map +1 -1
  22. package/dist/internal/useBuildDataSource.d.ts +3 -2
  23. package/dist/internal/useBuildSideEntityController.d.ts +3 -3
  24. package/dist/types/collections.d.ts +26 -2
  25. package/dist/types/fields.d.ts +4 -1
  26. package/dist/types/firecms.d.ts +3 -2
  27. package/dist/types/navigation.d.ts +9 -0
  28. package/dist/types/plugins.d.ts +13 -0
  29. package/dist/types/properties.d.ts +22 -1
  30. package/dist/types/side_entity_controller.d.ts +4 -0
  31. package/dist/util/callbacks.d.ts +2 -0
  32. package/dist/util/createFormexStub.d.ts +2 -0
  33. package/dist/util/index.d.ts +1 -0
  34. package/dist/util/navigation_utils.d.ts +2 -1
  35. package/dist/util/objects.d.ts +1 -1
  36. package/dist/util/property_utils.d.ts +2 -2
  37. package/dist/util/references.d.ts +2 -2
  38. package/dist/util/resolutions.d.ts +11 -6
  39. package/package.json +9 -6
  40. package/src/app/Scaffold.tsx +13 -3
  41. package/src/components/ArrayContainer.tsx +414 -282
  42. package/src/components/ClearFilterSortButton.tsx +1 -1
  43. package/src/components/ConfirmationDialog.tsx +9 -9
  44. package/src/components/DeleteEntityDialog.tsx +4 -2
  45. package/src/components/EntityCollectionTable/EntityCollectionRowActions.tsx +8 -6
  46. package/src/components/EntityCollectionTable/PropertyTableCell.tsx +1 -1
  47. package/src/components/EntityCollectionTable/internal/CollectionTableToolbar.tsx +1 -1
  48. package/src/components/EntityCollectionTable/internal/EntityTableCell.tsx +13 -2
  49. package/src/components/EntityCollectionTable/internal/popup_field/PopupFormField.tsx +58 -29
  50. package/src/components/EntityCollectionTable/internal/popup_field/useDraggable.tsx +9 -9
  51. package/src/components/EntityCollectionView/EntityCollectionView.tsx +26 -6
  52. package/src/components/EntityJsonPreview.tsx +66 -0
  53. package/src/components/EntityPreview.tsx +27 -16
  54. package/src/components/EntityView.tsx +4 -1
  55. package/src/components/ErrorView.tsx +1 -1
  56. package/src/components/HomePage/DefaultHomePage.tsx +2 -1
  57. package/src/components/HomePage/NavigationCardBinding.tsx +3 -1
  58. package/src/components/ReferenceTable/ReferenceSelectionTable.tsx +3 -1
  59. package/src/components/SelectableTable/SelectableTable.tsx +140 -143
  60. package/src/components/VirtualTable/VirtualTable.tsx +37 -31
  61. package/src/components/VirtualTable/VirtualTableProps.tsx +0 -5
  62. package/src/components/VirtualTable/fields/VirtualTableInput.tsx +0 -1
  63. package/src/components/common/default_entity_actions.tsx +15 -4
  64. package/src/components/index.tsx +2 -0
  65. package/src/core/DefaultAppBar.tsx +17 -5
  66. package/src/core/EntityEditView.tsx +135 -47
  67. package/src/core/EntitySidePanel.tsx +15 -20
  68. package/src/core/FireCMS.tsx +19 -12
  69. package/src/form/EntityForm.tsx +32 -24
  70. package/src/form/PropertyFieldBinding.tsx +8 -6
  71. package/src/form/components/CustomIdField.tsx +3 -1
  72. package/src/form/components/LabelWithIcon.tsx +1 -1
  73. package/src/form/field_bindings/ArrayCustomShapedFieldBinding.tsx +4 -1
  74. package/src/form/field_bindings/ArrayOfReferencesFieldBinding.tsx +4 -2
  75. package/src/form/field_bindings/BlockFieldBinding.tsx +1 -1
  76. package/src/form/field_bindings/KeyValueFieldBinding.tsx +1 -1
  77. package/src/form/field_bindings/MapFieldBinding.tsx +5 -4
  78. package/src/form/field_bindings/MarkdownEditorFieldBinding.tsx +6 -2
  79. package/src/form/field_bindings/MultiSelectFieldBinding.tsx +3 -3
  80. package/src/form/field_bindings/RepeatFieldBinding.tsx +9 -2
  81. package/src/form/field_bindings/SelectFieldBinding.tsx +3 -2
  82. package/src/form/field_bindings/StorageUploadFieldBinding.tsx +227 -156
  83. package/src/hooks/data/save.ts +24 -35
  84. package/src/hooks/useBuildNavigationController.tsx +42 -17
  85. package/src/hooks/useFireCMSContext.tsx +0 -30
  86. package/src/internal/useBuildDataSource.ts +9 -5
  87. package/src/internal/useBuildSideEntityController.tsx +26 -20
  88. package/src/preview/PropertyPreview.tsx +4 -2
  89. package/src/preview/components/ImagePreview.tsx +2 -2
  90. package/src/preview/components/ReferencePreview.tsx +1 -1
  91. package/src/preview/property_previews/ArrayOfMapsPreview.tsx +5 -4
  92. package/src/preview/property_previews/ArrayOfReferencesPreview.tsx +4 -3
  93. package/src/preview/property_previews/ArrayOfStorageComponentsPreview.tsx +4 -2
  94. package/src/preview/property_previews/ArrayOfStringsPreview.tsx +4 -3
  95. package/src/preview/property_previews/ArrayOneOfPreview.tsx +4 -2
  96. package/src/preview/property_previews/ArrayPropertyPreview.tsx +4 -2
  97. package/src/preview/property_previews/MapPropertyPreview.tsx +1 -1
  98. package/src/preview/property_previews/SkeletonPropertyComponent.tsx +1 -1
  99. package/src/preview/property_previews/StringPropertyPreview.tsx +1 -1
  100. package/src/routes/FireCMSRoute.tsx +15 -4
  101. package/src/types/collections.ts +31 -2
  102. package/src/types/fields.tsx +5 -1
  103. package/src/types/firecms.tsx +3 -3
  104. package/src/types/navigation.ts +11 -0
  105. package/src/types/plugins.tsx +17 -0
  106. package/src/types/properties.ts +27 -1
  107. package/src/types/side_entity_controller.tsx +5 -0
  108. package/src/util/callbacks.ts +119 -0
  109. package/src/util/createFormexStub.tsx +62 -0
  110. package/src/util/index.ts +1 -0
  111. package/src/util/join_collections.ts +3 -1
  112. package/src/util/navigation_from_path.ts +5 -1
  113. package/src/util/navigation_utils.ts +84 -20
  114. package/src/util/objects.ts +54 -17
  115. package/src/util/property_utils.tsx +7 -3
  116. package/src/util/references.ts +8 -6
  117. package/src/util/resolutions.ts +17 -9
  118. package/src/util/useStorageUploadController.tsx +21 -2
  119. package/dist/components/EntityCollectionTable/internal/popup_field/ElementResizeListener.d.ts +0 -5
  120. package/src/components/EntityCollectionTable/internal/popup_field/ElementResizeListener.tsx +0 -59
@@ -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: (updatedEntity: Entity<M>) => onSaveSuccess(updatedEntity),
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={"py-4 flex-grow line-clamp-1 " + (collection.hideIdFromForm ? "mb-2" : "mb-0")}
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={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={formContext.formex}>
683
+ <Formex value={formex}>
679
684
  <form
680
- onSubmit={formContext.formex.handleSubmit}
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
- {formContext.formex.dirty
693
- ? <Tooltip title={"Unsaved changes"}
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) => onChange(v as string)}
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
- includeAddButton={!property.disabled}
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
- includeAddButton={true}
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 className={cls("py-1 flex flex-col space-y-2", minimalistView && property.widthPercentage !== undefined ? "mt-8" : undefined)}>
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 = "medium",
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 === "medium" ? "medium" : "small"}
87
- value={validValue ? value.map((v) => v.toString()) : []}
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
- includeAddButton={!property.disabled}
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) => {