@firecms/core 3.0.0-canary.66 → 3.0.0-canary.68

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 (41) hide show
  1. package/dist/core/EntityEditView.d.ts +17 -3
  2. package/dist/form/PropertiesForm.d.ts +8 -0
  3. package/dist/form/components/FieldHelperText.d.ts +3 -3
  4. package/dist/form/components/StorageItemPreview.d.ts +2 -4
  5. package/dist/form/field_bindings/MapFieldBinding.d.ts +1 -1
  6. package/dist/form/field_bindings/StorageUploadFieldBinding.d.ts +2 -4
  7. package/dist/form/index.d.ts +0 -2
  8. package/dist/index.es.js +4271 -4322
  9. package/dist/index.es.js.map +1 -1
  10. package/dist/index.umd.js +5 -5
  11. package/dist/index.umd.js.map +1 -1
  12. package/dist/types/collections.d.ts +14 -0
  13. package/dist/types/fields.d.ts +31 -30
  14. package/dist/types/plugins.d.ts +2 -2
  15. package/dist/types/properties.d.ts +1 -1
  16. package/dist/util/storage.d.ts +23 -2
  17. package/dist/util/useStorageUploadController.d.ts +1 -1
  18. package/package.json +4 -4
  19. package/src/components/EntityCollectionTable/internal/popup_field/PopupFormField.tsx +2 -1
  20. package/src/core/EntityEditView.tsx +662 -120
  21. package/src/core/EntitySidePanel.tsx +0 -1
  22. package/src/form/PropertiesForm.tsx +81 -0
  23. package/src/form/PropertyFieldBinding.tsx +28 -5
  24. package/src/form/components/FieldHelperText.tsx +3 -3
  25. package/src/form/components/StorageItemPreview.tsx +0 -4
  26. package/src/form/field_bindings/MapFieldBinding.tsx +10 -3
  27. package/src/form/field_bindings/ReadOnlyFieldBinding.tsx +0 -7
  28. package/src/form/field_bindings/StorageUploadFieldBinding.tsx +3 -26
  29. package/src/form/index.tsx +4 -4
  30. package/src/form/validation.ts +1 -17
  31. package/src/types/collections.ts +14 -0
  32. package/src/types/customization_controller.tsx +0 -1
  33. package/src/types/fields.tsx +33 -33
  34. package/src/types/plugins.tsx +2 -2
  35. package/src/types/properties.ts +1 -1
  36. package/src/util/entities.ts +1 -0
  37. package/src/util/permissions.ts +1 -0
  38. package/src/util/storage.ts +75 -21
  39. package/src/util/useStorageUploadController.tsx +21 -3
  40. package/dist/form/EntityForm.d.ts +0 -77
  41. package/src/form/EntityForm.tsx +0 -735
@@ -79,7 +79,6 @@ export function EntitySidePanel(props: EntitySidePanelProps) {
79
79
  <ErrorBoundary>
80
80
  <EntityEditView
81
81
  {...props}
82
- formWidth={props.width}
83
82
  collection={collection}
84
83
  parentCollectionIds={parentCollectionIds}
85
84
  onValuesAreModified={onValuesAreModified}
@@ -0,0 +1,81 @@
1
+ import { FormContext, PropertiesOrBuilders, PropertyFieldBindingProps } from "../types";
2
+ import { Tooltip } from "@firecms/ui";
3
+ import { PropertyIdCopyTooltipContent } from "../components/PropertyIdCopyTooltipContent";
4
+ import { PropertyFieldBinding } from "./PropertyFieldBinding";
5
+ import { ErrorBoundary } from "../components";
6
+ import { isHidden, isReadOnly, resolveProperties } from "../util";
7
+ import { FormexController } from "@firecms/formex";
8
+
9
+ export type PropertiesFormProps<M extends Record<string, any> = Record<string, any>> = {
10
+ properties: PropertiesOrBuilders<M>;
11
+ propertiesOrder?: string[];
12
+ formex: FormexController<M>;
13
+ }
14
+
15
+ export function PropertiesForm<M extends Record<string, any> = Record<string, any>>({
16
+ properties,
17
+ propertiesOrder,
18
+ formex
19
+ }: PropertiesFormProps<M>) {
20
+
21
+ const resolvedProperties = resolveProperties({ properties });
22
+
23
+ const formContext: FormContext<M> = {
24
+ // @ts-ignore
25
+ setFieldValue: useCallback(formex.setFieldValue, []),
26
+ values: formex.values ?? {},
27
+ // @ts-ignore
28
+ save: useCallback(() => {
29
+ throw new Error("Not implemented. You currently can't call save from a custom field, within a PropertiesForm (it works in standard Entity forms)");
30
+ }, []),
31
+ formex
32
+ };
33
+
34
+ const formFields = (
35
+ <div className={"flex flex-col gap-8"}>
36
+ {(propertiesOrder ?? Object.keys(resolvedProperties))
37
+ .map((key) => {
38
+
39
+ const property = resolvedProperties[key];
40
+ if (!property) {
41
+ console.warn(`Property ${key} not found in collection PropertiesForm`);
42
+ return null;
43
+ }
44
+
45
+ const disabled = formex.isSubmitting || isReadOnly(property) || Boolean(property.disabled);
46
+ const hidden = isHidden(property);
47
+ if (hidden) return null;
48
+ const cmsFormFieldProps: PropertyFieldBindingProps<any, M> = {
49
+ propertyKey: key,
50
+ disabled,
51
+ property,
52
+ includeDescription: property.description || property.longDescription,
53
+ context: formContext,
54
+ tableMode: false,
55
+ partOfArray: false,
56
+ partOfBlock: false,
57
+ autoFocus: false
58
+ };
59
+
60
+ return (
61
+ <div id={`form_field_${key}`}
62
+ key={`field_${key}`}>
63
+ <ErrorBoundary>
64
+ <Tooltip title={<PropertyIdCopyTooltipContent propertyId={key}/>}
65
+ delayDuration={800}
66
+ side={"left"}
67
+ align={"start"}
68
+ sideOffset={16}>
69
+ <PropertyFieldBinding {...cmsFormFieldProps}/>
70
+ </Tooltip>
71
+ </ErrorBoundary>
72
+ </div>
73
+ );
74
+ })
75
+ .filter(Boolean)}
76
+
77
+ </div>
78
+ );
79
+
80
+ return <div></div>
81
+ }
@@ -110,7 +110,12 @@ function PropertyFieldBindingInternal<T extends CMSType = CMSType, M extends Rec
110
110
  } else {
111
111
  const propertyConfig = getFieldConfig(resolvedProperty, customizationController.propertyConfigs);
112
112
  if (!propertyConfig) {
113
- console.log("INTERNAL: Could not find field config for property", { propertyKey, resolvedProperty, fields: customizationController.propertyConfigs, propertyConfig });
113
+ console.log("INTERNAL: Could not find field config for property", {
114
+ propertyKey,
115
+ resolvedProperty,
116
+ fields: customizationController.propertyConfigs,
117
+ propertyConfig
118
+ });
114
119
  throw new Error(`INTERNAL: Could not find field config for property ${propertyKey}`);
115
120
  }
116
121
  const configProperty = resolveProperty({
@@ -194,7 +199,14 @@ function FieldInternal<T extends CMSType, CustomProps, M extends Record<string,
194
199
  (fieldProps.form.submitCount > 0 || property.validation?.unique) &&
195
200
  (!Array.isArray(error) || !!error.filter((e: any) => !!e).length);
196
201
 
197
- const WrappedComponent: ComponentType<FieldProps<T, any, M>> | null = useWrappedComponent(context.path, context.collection, propertyKey, property, Component, plugins);
202
+ const WrappedComponent: ComponentType<FieldProps<T, any, M>> | null = useWrappedComponent({
203
+ path: context.path,
204
+ collection: context.collection,
205
+ propertyKey: propertyKey,
206
+ property: property,
207
+ Component: Component,
208
+ plugins: plugins
209
+ });
198
210
  const UsedComponent: ComponentType<FieldProps<T>> = WrappedComponent ?? Component;
199
211
 
200
212
  const isSubmitting = fieldProps.form.isSubmitting;
@@ -264,13 +276,24 @@ const shouldPropertyReRender = (property: PropertyOrBuilder | ResolvedProperty,
264
276
  }
265
277
  }
266
278
 
267
- function useWrappedComponent<T extends CMSType = CMSType, M extends Record<string, any> = any>(
268
- path: string,
269
- collection: EntityCollection<M>,
279
+ interface UseWrappedComponentParams<T extends CMSType = CMSType, M extends Record<string, any> = any> {
280
+ path?: string,
281
+ collection?: EntityCollection<M>,
270
282
  propertyKey: string,
271
283
  property: ResolvedProperty<T>,
272
284
  Component: ComponentType<FieldProps<T, any, M>>,
273
285
  plugins?: FireCMSPlugin[]
286
+ }
287
+
288
+ function useWrappedComponent<T extends CMSType = CMSType, M extends Record<string, any> = any>(
289
+ {
290
+ path,
291
+ collection,
292
+ propertyKey,
293
+ property,
294
+ Component,
295
+ plugins
296
+ }: UseWrappedComponentParams<T, M>
274
297
  ): ComponentType<FieldProps<T, any, M>> | null {
275
298
 
276
299
  const wrapperRef = useRef<ComponentType<FieldProps<T, any, M>> | null>((() => {
@@ -1,4 +1,4 @@
1
- import { ResolvedProperty } from "../../types";
1
+ import { Property, ResolvedProperty } from "../../types";
2
2
  import { IconButton, InfoIcon, Tooltip, Typography } from "@firecms/ui";
3
3
 
4
4
  /**
@@ -13,8 +13,8 @@ export function FieldHelperText({
13
13
  disabled
14
14
  }: {
15
15
  error?: string,
16
- showError: boolean,
17
- property: ResolvedProperty,
16
+ showError?: boolean,
17
+ property: ResolvedProperty | Property,
18
18
  includeDescription?: boolean,
19
19
  disabled?: boolean,
20
20
  }
@@ -10,22 +10,18 @@ interface StorageItemPreviewProps {
10
10
  name: string;
11
11
  property: ResolvedStringProperty;
12
12
  value: string,
13
- entity: Entity<any>,
14
13
  onRemove: (value: string) => void;
15
14
  size: PreviewSize;
16
15
  disabled: boolean;
17
- collection: EntityCollection;
18
16
  }
19
17
 
20
18
  export function StorageItemPreview({
21
19
  name,
22
20
  property,
23
21
  value,
24
- entity,
25
22
  onRemove,
26
23
  disabled,
27
24
  size,
28
- collection
29
25
  }: StorageItemPreviewProps) {
30
26
 
31
27
  return (
@@ -1,5 +1,13 @@
1
1
  import React from "react";
2
- import { FieldProps, Properties, ResolvedProperties } from "../../types";
2
+ import {
3
+ CMSType,
4
+ FieldProps,
5
+ FormContext,
6
+ MapProperty,
7
+ Properties,
8
+ ResolvedProperties,
9
+ ResolvedProperty
10
+ } from "../../types";
3
11
 
4
12
  import { ErrorBoundary } from "../../components";
5
13
  import { getIconForProperty, isHidden, pick } from "../../util";
@@ -21,7 +29,6 @@ export function MapFieldBinding({
21
29
  error,
22
30
  disabled,
23
31
  property,
24
- setValue,
25
32
  partOfBlock,
26
33
  tableMode,
27
34
  includeDescription,
@@ -101,7 +108,7 @@ export function MapFieldBinding({
101
108
  {(tableMode || partOfBlock) && mapFormView}
102
109
 
103
110
  <FieldHelperText includeDescription={includeDescription}
104
- showError={showError}
111
+ showError={showError ?? false}
105
112
  error={error ? (typeof error === "string" ? error : "A property of this map has an error") : undefined}
106
113
  disabled={disabled}
107
114
  property={property}/>
@@ -30,12 +30,6 @@ export function ReadOnlyFieldBinding({
30
30
  if (!context.entityId)
31
31
  throw new Error("ReadOnlyFieldBinding: Entity id is null");
32
32
 
33
- const entity: Entity<any> = {
34
- id: context.entityId!,
35
- values: context.values,
36
- path: context.path
37
- };
38
-
39
33
  return (
40
34
 
41
35
  <>
@@ -53,7 +47,6 @@ export function ReadOnlyFieldBinding({
53
47
  <PropertyPreview propertyKey={propertyKey}
54
48
  value={value}
55
49
  property={property}
56
- // entity={entity}
57
50
  size={"medium"}/>
58
51
  </ErrorBoundary>
59
52
 
@@ -3,7 +3,6 @@ import React, { useCallback } from "react";
3
3
  import {
4
4
  ArrayProperty,
5
5
  Entity,
6
- EntityCollection,
7
6
  FieldProps,
8
7
  ResolvedArrayProperty,
9
8
  ResolvedStringProperty,
@@ -81,7 +80,7 @@ export function StorageUploadFieldBinding({
81
80
  propertyKey,
82
81
  value,
83
82
  storageSource,
84
- disabled,
83
+ disabled: disabled ?? false,
85
84
  onChange: setValue
86
85
  });
87
86
 
@@ -91,12 +90,6 @@ export function StorageUploadFieldBinding({
91
90
  setValue
92
91
  });
93
92
 
94
- const entity: Entity<any> = {
95
- id: context.entityId,
96
- values: context.values,
97
- path: context.path
98
- };
99
-
100
93
  return (
101
94
 
102
95
  <>
@@ -109,15 +102,13 @@ export function StorageUploadFieldBinding({
109
102
 
110
103
  <StorageUpload
111
104
  value={internalValue}
112
- collection={context.collection}
113
105
  name={propertyKey}
114
- disabled={disabled}
115
- autoFocus={autoFocus}
106
+ disabled={disabled ?? false}
107
+ autoFocus={autoFocus ?? false}
116
108
  property={property}
117
109
  onChange={setValue}
118
110
  setInternalValue={setInternalValue}
119
111
  onFilesAdded={onFilesAdded}
120
- entity={entity}
121
112
  onFileUploadComplete={onFileUploadComplete}
122
113
  storagePathBuilder={storagePathBuilder}
123
114
  storage={storage}
@@ -135,7 +126,6 @@ export function StorageUploadFieldBinding({
135
126
 
136
127
  function FileDropComponent({
137
128
  storage,
138
- collection,
139
129
  disabled,
140
130
  isDraggingOver,
141
131
  onFilesAdded,
@@ -144,7 +134,6 @@ function FileDropComponent({
144
134
  autoFocus,
145
135
  internalValue,
146
136
  property,
147
- entity,
148
137
  onClear,
149
138
  metadata,
150
139
  storagePathBuilder,
@@ -154,7 +143,6 @@ function FileDropComponent({
154
143
  helpText
155
144
  }: {
156
145
  storage: StorageConfig,
157
- collection: EntityCollection,
158
146
  disabled: boolean,
159
147
  isDraggingOver: boolean,
160
148
  droppableProvided: any,
@@ -165,7 +153,6 @@ function FileDropComponent({
165
153
  property: ResolvedStringProperty,
166
154
  onClear: (clearedStoragePathOrDownloadUrl: string) => void,
167
155
  metadata: any,
168
- entity: Entity<any>;
169
156
  storagePathBuilder: (file: File) => string,
170
157
  onFileUploadComplete: (uploadedPath: string, entry: StorageFieldItem, fileMetadata?: any) => Promise<void>,
171
158
  size: PreviewSize,
@@ -235,11 +222,9 @@ function FileDropComponent({
235
222
  if (entry.storagePathOrDownloadUrl) {
236
223
  child = (
237
224
  <StorageItemPreview
238
- collection={collection}
239
225
  name={`storage_preview_${entry.storagePathOrDownloadUrl}`}
240
226
  property={property}
241
227
  disabled={disabled}
242
- entity={entity}
243
228
  value={entry.storagePathOrDownloadUrl}
244
229
  onRemove={onClear}
245
230
  size={entry.size}/>
@@ -299,7 +284,6 @@ function FileDropComponent({
299
284
 
300
285
  export interface StorageUploadProps {
301
286
  value: StorageFieldItem[];
302
- collection: EntityCollection;
303
287
  setInternalValue: (v: StorageFieldItem[]) => void;
304
288
  name: string;
305
289
  property: ResolvedStringProperty | ResolvedArrayProperty<string[]>;
@@ -307,7 +291,6 @@ export interface StorageUploadProps {
307
291
  multipleFilesSupported: boolean;
308
292
  autoFocus: boolean;
309
293
  disabled: boolean;
310
- entity: Entity<any>;
311
294
  storage: StorageConfig;
312
295
  onFilesAdded: (acceptedFiles: File[]) => void;
313
296
  storagePathBuilder: (file: File) => string;
@@ -315,7 +298,6 @@ export interface StorageUploadProps {
315
298
  }
316
299
 
317
300
  export function StorageUpload({
318
- collection,
319
301
  property,
320
302
  name,
321
303
  value,
@@ -327,7 +309,6 @@ export function StorageUpload({
327
309
  onFilesAdded,
328
310
  autoFocus,
329
311
  storage,
330
- entity,
331
312
  storagePathBuilder,
332
313
  }: StorageUploadProps) {
333
314
 
@@ -408,11 +389,9 @@ export function StorageUpload({
408
389
  className="rounded"
409
390
  >
410
391
  <StorageItemPreview
411
- collection={collection}
412
392
  name={`storage_preview_${entry.storagePathOrDownloadUrl}`}
413
393
  property={renderProperty}
414
394
  disabled={true}
415
- entity={entity}
416
395
  value={entry.storagePathOrDownloadUrl as string}
417
396
  onRemove={onClear}
418
397
  size={entry.size}/>
@@ -422,7 +401,6 @@ export function StorageUpload({
422
401
  >
423
402
  {(provided, snapshot) => {
424
403
  return <FileDropComponent storage={storage}
425
- collection={collection}
426
404
  disabled={disabled}
427
405
  isDraggingOver={snapshot.isDraggingOver}
428
406
  droppableProvided={provided}
@@ -431,7 +409,6 @@ export function StorageUpload({
431
409
  autoFocus={autoFocus}
432
410
  internalValue={value}
433
411
  property={renderProperty}
434
- entity={entity}
435
412
  onClear={onClear}
436
413
  metadata={metadata}
437
414
  storagePathBuilder={storagePathBuilder}
@@ -34,10 +34,10 @@ export {
34
34
 
35
35
  export * from "./components";
36
36
 
37
- export type { EntityFormProps } from "./EntityForm";
38
- export {
39
- EntityForm
40
- } from "./EntityForm";
37
+ // export type { EntityFormProps } from "./EntityForm";
38
+ // export {
39
+ // EntityForm
40
+ // } from "./EntityForm";
41
41
 
42
42
  export { PropertyFieldBinding } from "./PropertyFieldBinding";
43
43
  export * from "./useClearRestoreValue";
@@ -112,23 +112,7 @@ export function getYupMapObjectSchema({
112
112
  if (validation?.required) {
113
113
  return shape.required(validation?.requiredMessage ? validation.requiredMessage : "Required").nullable(true);
114
114
  }
115
- return shape.nullable(true);
116
- // const object: ObjectSchema<any> = yup.object().shape(objectSchema);
117
- // return validation?.required
118
- // ? object.required(validation?.requiredMessage ? validation.requiredMessage : "Required").nullable(true)
119
- // : yup.object().optional().default(undefined).notRequired().nullable(true).test(
120
- // "empty-check",
121
- // "Optional map can be empty",
122
- // (o: any, testContext: any) => {
123
- // try {
124
- // if (!o || Object.keys(o).length === 0) return true;
125
- // return object.validateSync(o);
126
- // } catch (e) {
127
- // testContext.createError(e);
128
- // console.error(e);
129
- // return false;
130
- // }
131
- // });
115
+ return yup.object().shape(shape.fields).default(undefined).notRequired().nullable(true);
132
116
  }
133
117
 
134
118
  function getYupStringSchema({
@@ -477,8 +477,22 @@ export interface AdditionalFieldDelegate<M extends Record<string, any> = any,
477
477
  */
478
478
  export type EntityCustomView<M extends Record<string, any> = any> =
479
479
  {
480
+ /**
481
+ * Key of this custom view.
482
+ */
480
483
  key: string,
484
+ /**
485
+ * Name of this custom view.
486
+ */
481
487
  name: string,
488
+ /**
489
+ * If set to true, the actions of the entity will be included in the
490
+ * bottom of the panel (save buttons, delete buttons, etc.)
491
+ */
492
+ includeActions?: boolean;
493
+ /**
494
+ * Builder for rendering the custom view
495
+ */
482
496
  Builder?: React.ComponentType<EntityCustomViewParams<M>>;
483
497
  }
484
498
 
@@ -24,7 +24,6 @@ export type CustomizationController = {
24
24
  *
25
25
  * You can also define an entity view from the UI.
26
26
  */
27
-
28
27
  entityViews?: EntityCustomView[];
29
28
 
30
29
  /**
@@ -1,6 +1,6 @@
1
- import { EntityValues } from "./entities";
2
1
  import { CMSType, PropertyOrBuilder } from "./properties";
3
2
  import { ResolvedEntityCollection, ResolvedProperty } from "./resolved_entities";
3
+ import { FormexController } from "@firecms/formex";
4
4
 
5
5
  /**
6
6
  * When building a custom field you need to create a React component that takes
@@ -21,11 +21,6 @@ export interface FieldProps<T extends CMSType = any, CustomProps = any, M extend
21
21
  */
22
22
  value: T;
23
23
 
24
- /**
25
- * Initial value of this field
26
- */
27
- // initialValue: T | undefined;
28
-
29
24
  /**
30
25
  * Set value of field directly
31
26
  */
@@ -42,7 +37,7 @@ export interface FieldProps<T extends CMSType = any, CustomProps = any, M extend
42
37
  /**
43
38
  * Is the form currently submitting
44
39
  */
45
- isSubmitting: boolean;
40
+ isSubmitting?: boolean;
46
41
 
47
42
  /**
48
43
  * Should this field show the error indicator.
@@ -50,19 +45,19 @@ export interface FieldProps<T extends CMSType = any, CustomProps = any, M extend
50
45
  * filled) but we don't want to show the error until the user has tried
51
46
  * saving.
52
47
  */
53
- showError: boolean;
48
+ showError?: boolean;
54
49
 
55
50
  /**
56
51
  * Is there an error in this field. The error field has the same shape as
57
52
  * the field, replacing values with a string containing the error.
58
53
  * It takes the value `null` if there is no error
59
54
  */
60
- error: any | null;
55
+ error?: any | null;
61
56
 
62
57
  /**
63
58
  * Has this field been touched
64
59
  */
65
- touched: boolean;
60
+ touched?: boolean;
66
61
 
67
62
  /**
68
63
  * Property related to this field
@@ -72,38 +67,38 @@ export interface FieldProps<T extends CMSType = any, CustomProps = any, M extend
72
67
  /**
73
68
  * Should this field include a description
74
69
  */
75
- includeDescription: boolean;
70
+ includeDescription?: boolean;
76
71
 
77
72
  /**
78
73
  * Flag to indicate that the underlying value has been updated in the
79
74
  * datasource
80
75
  */
81
- underlyingValueHasChanged: boolean;
76
+ underlyingValueHasChanged?: boolean;
82
77
 
83
78
  /**
84
79
  * Is this field part of an array
85
80
  */
86
- partOfArray: boolean;
81
+ partOfArray?: boolean;
87
82
 
88
83
  /**
89
84
  * Is this field part of a block (oneOf array)
90
85
  */
91
- partOfBlock: boolean;
86
+ partOfBlock?: boolean;
92
87
 
93
88
  /**
94
89
  * Is this field being rendered in the entity table popup
95
90
  */
96
- tableMode: boolean;
91
+ tableMode?: boolean;
97
92
 
98
93
  /**
99
94
  * Should this field autofocus on mount
100
95
  */
101
- autoFocus: boolean;
96
+ autoFocus?: boolean;
102
97
 
103
98
  /**
104
99
  * Additional properties set by the developer
105
100
  */
106
- customProps: CustomProps
101
+ customProps?: CustomProps
107
102
 
108
103
  /**
109
104
  * Additional values related to the state of the form or the entity
@@ -113,7 +108,7 @@ export interface FieldProps<T extends CMSType = any, CustomProps = any, M extend
113
108
  /**
114
109
  * Flag to indicate if this field should be disabled
115
110
  */
116
- disabled: boolean;
111
+ disabled?: boolean;
117
112
 
118
113
  }
119
114
 
@@ -124,37 +119,42 @@ export interface FieldProps<T extends CMSType = any, CustomProps = any, M extend
124
119
  export interface FormContext<M extends Record<string, any> = any> {
125
120
 
126
121
  /**
127
- * Collection of the entity being modified
122
+ * Current values of the entity
128
123
  */
129
- collection: ResolvedEntityCollection<M>;
124
+ values: M;
130
125
 
131
126
  /**
132
- * Current values of the entity
127
+ * Update the value of a field
128
+ * @param key
129
+ * @param value
130
+ * @param shouldValidate
133
131
  */
134
- values: EntityValues<M>;
132
+ setFieldValue: (key: string, value: any, shouldValidate?: boolean) => void;
135
133
 
136
134
  /**
137
- * Entity id, it can be null if it's a new entity
135
+ * Save the entity.
138
136
  */
139
- entityId?: string;
137
+ save: (values: M) => void;
140
138
 
141
139
  /**
142
- * Path this entity is located at
140
+ * Collection of the entity being modified
143
141
  */
144
- path: string;
142
+ collection?: ResolvedEntityCollection<M>;
145
143
 
146
144
  /**
147
- * Update the value of a field
148
- * @param key
149
- * @param value
150
- * @param shouldValidate
145
+ * Entity id, it can be null if it's a new entity
151
146
  */
152
- setFieldValue: (key: string, value: any, shouldValidate?: boolean) => void;
147
+ entityId?: string;
148
+
149
+ /**
150
+ * Path this entity is located at
151
+ */
152
+ path?: string;
153
153
 
154
154
  /**
155
- * Save the entity
155
+ * This is the underlying formex controller that powers the form
156
156
  */
157
- save: (values: EntityValues<M>) => void;
157
+ formex: FormexController<M>;
158
158
  }
159
159
 
160
160
  /**
@@ -194,8 +194,8 @@ export type PluginFieldBuilderParams<T extends CMSType = CMSType, M extends Reco
194
194
  property: Property<T> | ResolvedProperty<T>;
195
195
  Field: React.ComponentType<FieldProps<T, any, M>>;
196
196
  plugin: FireCMSPlugin;
197
- path: string;
198
- collection: EC;
197
+ path?: string;
198
+ collection?: EC;
199
199
  };
200
200
 
201
201
  export interface PluginGenericProps<UserType extends User = User> {
@@ -812,7 +812,7 @@ export interface UploadedFileContext {
812
812
  /**
813
813
  * Entity path. E.g. `products/PID/locales`
814
814
  */
815
- path: string;
815
+ path?: string;
816
816
 
817
817
  /**
818
818
  * Values of the current entity
@@ -152,6 +152,7 @@ export function traverseValuesProperties<M extends Record<string, any>>(
152
152
  .map(([key, property]) => {
153
153
  const inputValue = inputValues && (inputValues)[key];
154
154
  const updatedValue = traverseValueProperty(inputValue, property as Property, operation);
155
+ if (updatedValue === null) return null;
155
156
  if (updatedValue === undefined) return undefined;
156
157
  return ({ [key]: updatedValue });
157
158
  })
@@ -49,6 +49,7 @@ export function canCreateEntity<M extends Record<string, any>, UserType extends
49
49
  authController: AuthController<UserType>,
50
50
  path: string,
51
51
  entity: Entity<M> | null): boolean {
52
+ if (collection.collectionGroup) return false;
52
53
  return resolvePermissions(collection, authController, path, entity)?.create ?? DEFAULT_PERMISSIONS.create;
53
54
  }
54
55