@firecms/core 3.0.0-alpha.35 → 3.0.0-alpha.36

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 (48) hide show
  1. package/dist/core/FireCMS.d.ts +0 -1
  2. package/dist/form/form_field_configs.d.ts +1 -1
  3. package/dist/hooks/useBuildDataSource.d.ts +2 -4
  4. package/dist/index.es.js +5884 -5825
  5. package/dist/index.es.js.map +1 -1
  6. package/dist/index.umd.js +14 -14
  7. package/dist/index.umd.js.map +1 -1
  8. package/dist/types/firecms.d.ts +1 -1
  9. package/dist/types/firecms_context.d.ts +1 -1
  10. package/dist/types/plugins.d.ts +1 -0
  11. package/dist/util/builders.d.ts +64 -0
  12. package/dist/util/index.d.ts +1 -0
  13. package/dist/util/objects.d.ts +1 -0
  14. package/package.json +138 -138
  15. package/src/components/EntityCollectionTable/internal/DeleteEntityDialog.tsx +1 -1
  16. package/src/components/EntityCollectionTable/internal/PropertyTableCell.tsx +2 -1
  17. package/src/components/EntityCollectionTable/internal/popup_field/PopupFormField.tsx +1 -1
  18. package/src/components/EntityCollectionView/EntityCollectionView.tsx +5 -4
  19. package/src/components/EntityPreview.tsx +1 -1
  20. package/src/components/ErrorView.tsx +1 -0
  21. package/src/components/FireCMSAppBar.tsx +0 -1
  22. package/src/components/HomePage/DefaultHomePage.tsx +10 -0
  23. package/src/components/ReferenceSelectionInner.tsx +2 -2
  24. package/src/core/FireCMS.tsx +6 -5
  25. package/src/form/EntityForm.tsx +3 -3
  26. package/src/form/PropertyFieldBinding.tsx +4 -4
  27. package/src/form/components/ReferenceWidget.tsx +1 -1
  28. package/src/form/field_bindings/ArrayCustomShapedFieldBinding.tsx +1 -1
  29. package/src/form/field_bindings/ReferenceFieldBinding.tsx +2 -2
  30. package/src/form/form_field_configs.tsx +2 -2
  31. package/src/hooks/data/save.ts +3 -3
  32. package/src/hooks/useBuildDataSource.ts +3 -5
  33. package/src/preview/PropertyPreview.tsx +1 -1
  34. package/src/preview/components/ReferencePreview.tsx +2 -2
  35. package/src/preview/property_previews/ArrayOfMapsPreview.tsx +1 -1
  36. package/src/preview/property_previews/ArrayOfReferencesPreview.tsx +1 -1
  37. package/src/preview/property_previews/ArrayOfStorageComponentsPreview.tsx +1 -1
  38. package/src/preview/property_previews/ArrayOfStringsPreview.tsx +1 -1
  39. package/src/preview/property_previews/ArrayOneOfPreview.tsx +1 -1
  40. package/src/preview/property_previews/ArrayPropertyPreview.tsx +1 -1
  41. package/src/types/firecms.tsx +1 -1
  42. package/src/types/firecms_context.tsx +2 -1
  43. package/src/types/plugins.tsx +1 -0
  44. package/src/ui/Select.tsx +5 -9
  45. package/src/util/builders.ts +138 -0
  46. package/src/util/index.ts +1 -0
  47. package/src/util/objects.ts +23 -0
  48. package/src/util/resolutions.ts +6 -3
@@ -102,7 +102,7 @@ function PropertyFieldBindingInternal<T extends CMSType = CMSType, CustomProps =
102
102
  values: fieldProps.form.values,
103
103
  path: context.path,
104
104
  entityId: context.entityId,
105
- fields: fireCMSContext.fields
105
+ fields: fireCMSContext.propertyConfigs
106
106
  });
107
107
 
108
108
  if (resolvedProperty === null || isHidden(resolvedProperty)) {
@@ -114,9 +114,9 @@ function PropertyFieldBindingInternal<T extends CMSType = CMSType, CustomProps =
114
114
  Component = resolvedProperty.Field as ComponentType<FieldProps<any>>;
115
115
  }
116
116
  } else {
117
- const propertyConfig = getFieldConfig(resolvedProperty, fireCMSContext.fields);
117
+ const propertyConfig = getFieldConfig(resolvedProperty, fireCMSContext.propertyConfigs);
118
118
  if (!propertyConfig) {
119
- console.log("INTERNAL: Could not find field config for property", { propertyKey, resolvedProperty, fields: fireCMSContext.fields, propertyConfig });
119
+ console.log("INTERNAL: Could not find field config for property", { propertyKey, resolvedProperty, fields: fireCMSContext.propertyConfigs, propertyConfig });
120
120
  throw new Error(`INTERNAL: Could not find field config for property ${propertyKey}`);
121
121
  }
122
122
  const configProperty = resolveProperty({
@@ -125,7 +125,7 @@ function PropertyFieldBindingInternal<T extends CMSType = CMSType, CustomProps =
125
125
  values: fieldProps.form.values,
126
126
  path: context.path,
127
127
  entityId: context.entityId,
128
- fields: fireCMSContext.fields
128
+ fields: fireCMSContext.propertyConfigs
129
129
  });
130
130
  Component = configProperty.Field as ComponentType<FieldProps<T>>;
131
131
  }
@@ -135,7 +135,7 @@ export function ReferenceWidget<M extends Record<string, any>>({
135
135
  } else {
136
136
  if (validValue) {
137
137
 
138
- const listProperties = getReferencePreviewKeys(collection, fireCMSContext.fields, previewProperties, 3);
138
+ const listProperties = getReferencePreviewKeys(collection, fireCMSContext.propertyConfigs, previewProperties, 3);
139
139
 
140
140
  body = (
141
141
  <div className="flex flex-col flex-grow ml-4 mr-4">
@@ -28,7 +28,7 @@ export function ArrayCustomShapedFieldBinding<T extends Array<any>>({
28
28
  disabled
29
29
  }: FieldProps<T, any, any>) {
30
30
 
31
- const { fields } = useFireCMSContext();
31
+ const { propertyConfigs } = useFireCMSContext();
32
32
  if (!Array.isArray(property.resolvedProperties))
33
33
  throw Error("ArrayCustomShapedFieldBinding misconfiguration. Property `of` not set");
34
34
 
@@ -60,8 +60,8 @@ function ReferenceFieldBindingInternal<M extends Record<string, any>>({
60
60
  throw Error(`Couldn't find the corresponding collection for the path: ${property.path}`);
61
61
  }
62
62
 
63
- const onSingleEntitySelected = useCallback((e: Entity<any>) => {
64
- setValue(getReferenceFrom(e));
63
+ const onSingleEntitySelected = useCallback((e: Entity<any> | null) => {
64
+ setValue(e ? getReferenceFrom(e) : null);
65
65
  }, [setValue]);
66
66
 
67
67
  const referenceDialogController = useReferenceDialog({
@@ -313,7 +313,7 @@ export const DEFAULT_FIELD_CONFIGS: Record<string, PropertyConfig<any>> = {
313
313
  }
314
314
  };
315
315
 
316
- export function getFieldConfig(property: Property | ResolvedProperty, customFields: Record<string, PropertyConfig<any>>): PropertyConfig | undefined {
316
+ export function getFieldConfig(property: Property | ResolvedProperty, propertyConfigs: Record<string, PropertyConfig<any>>): PropertyConfig | undefined {
317
317
  const fieldId = getFieldId(property);
318
318
  const defaultFieldId = getDefaultFieldId(property);
319
319
  // console.log("fieldId", { fieldId });
@@ -322,7 +322,7 @@ export function getFieldConfig(property: Property | ResolvedProperty, customFiel
322
322
  return undefined;
323
323
  }
324
324
  const defaultFieldConfig = DEFAULT_FIELD_CONFIGS[defaultFieldId];
325
- const customField = fieldId ? customFields[fieldId] : undefined;
325
+ const customField = fieldId ? propertyConfigs[fieldId] : undefined;
326
326
  return mergeDeep(defaultFieldConfig ?? {}, customField ?? {});
327
327
  }
328
328
 
@@ -72,7 +72,7 @@ export async function saveEntityWithCallbacks<M extends Record<string, any>, Use
72
72
  path,
73
73
  values: previousValues as EntityValues<M>,
74
74
  entityId,
75
- fields: context.fields
75
+ fields: context.propertyConfigs
76
76
  });
77
77
  updatedValues = await callbacks.onPreSave({
78
78
  collection: resolvedCollection,
@@ -109,7 +109,7 @@ export async function saveEntityWithCallbacks<M extends Record<string, any>, Use
109
109
  path,
110
110
  values: updatedValues as EntityValues<M>,
111
111
  entityId,
112
- fields: context.fields
112
+ fields: context.propertyConfigs
113
113
  });
114
114
  callbacks.onSaveSuccess({
115
115
  collection: resolvedCollection,
@@ -137,7 +137,7 @@ export async function saveEntityWithCallbacks<M extends Record<string, any>, Use
137
137
  path,
138
138
  values: updatedValues as EntityValues<M>,
139
139
  entityId,
140
- fields: context.fields
140
+ fields: context.propertyConfigs
141
141
  });
142
142
  callbacks.onSaveFailure({
143
143
  collection: resolvedCollection,
@@ -22,16 +22,14 @@ import { resolveCollection, updateDateAutoValues } from "../util";
22
22
  /**
23
23
  * Use this hook to build a {@link DataSource} based on Firestore
24
24
  * @param firebaseApp
25
- * @param textSearchController
26
- * @param collectionRegistry
27
25
  * @group Firebase
28
26
  */
29
27
  export function useBuildDataSource({
30
28
  delegate,
31
- customFields
29
+ propertyConfigs
32
30
  }: {
33
31
  delegate: DataSourceDelegate,
34
- customFields: Record<string, PropertyConfig>;
32
+ propertyConfigs?: Record<string, PropertyConfig>;
35
33
  }): DataSource {
36
34
 
37
35
  return {
@@ -196,7 +194,7 @@ export function useBuildDataSource({
196
194
  collection,
197
195
  path,
198
196
  entityId,
199
- fields: customFields
197
+ fields: propertyConfigs
200
198
  });
201
199
 
202
200
  const properties: ResolvedProperties<M> = resolvedCollection.properties;
@@ -52,7 +52,7 @@ export function PropertyPreview<T extends CMSType>(props: PropertyPreviewProps<T
52
52
  propertyKey,
53
53
  propertyOrBuilder: inputProperty,
54
54
  propertyValue: value,
55
- fields: fireCMSContext.fields
55
+ fields: fireCMSContext.propertyConfigs
56
56
  });
57
57
 
58
58
  if (value === undefined || property === null) {
@@ -111,10 +111,10 @@ function ReferencePreviewExisting<M extends Record<string, any> = any>({ referen
111
111
  collection,
112
112
  path: reference.path,
113
113
  values: usedEntity?.values,
114
- fields: context.fields
114
+ fields: context.propertyConfigs
115
115
  }), [collection]);
116
116
 
117
- const listProperties = useMemo(() => getReferencePreviewKeys(resolvedCollection, context.fields, previewProperties, size === "small" || size === "medium" ? 3 : 1),
117
+ const listProperties = useMemo(() => getReferencePreviewKeys(resolvedCollection, context.propertyConfigs, previewProperties, size === "small" || size === "medium" ? 3 : 1),
118
118
  [previewProperties, resolvedCollection, size]);
119
119
 
120
120
  let body: React.ReactNode;
@@ -21,7 +21,7 @@ export function ArrayOfMapsPreview({
21
21
  propertyKey,
22
22
  property: inputProperty,
23
23
  propertyValue: value,
24
- fields: fireCMSContext.fields
24
+ fields: fireCMSContext.propertyConfigs
25
25
  });
26
26
 
27
27
  if (Array.isArray(property?.of)) {
@@ -19,7 +19,7 @@ export function ArrayOfReferencesPreview({
19
19
  propertyKey,
20
20
  property: inputProperty,
21
21
  propertyValue: value,
22
- fields: fireCMSContext.fields
22
+ fields: fireCMSContext.propertyConfigs
23
23
  });
24
24
 
25
25
  if (Array.isArray(property?.of)) {
@@ -24,7 +24,7 @@ export function ArrayOfStorageComponentsPreview({
24
24
  propertyKey,
25
25
  property: inputProperty,
26
26
  propertyValue: value,
27
- fields: fireCMSContext.fields
27
+ fields: fireCMSContext.propertyConfigs
28
28
  });
29
29
 
30
30
  if (Array.isArray(property.of)) {
@@ -22,7 +22,7 @@ export function ArrayOfStringsPreview({
22
22
  propertyKey,
23
23
  property: inputProperty,
24
24
  propertyValue: value,
25
- fields: fireCMSContext.fields
25
+ fields: fireCMSContext.propertyConfigs
26
26
  });
27
27
 
28
28
  if (Array.isArray(property.of)) {
@@ -25,7 +25,7 @@ export function ArrayOneOfPreview({
25
25
  propertyKey,
26
26
  property: inputProperty,
27
27
  propertyValue: value,
28
- fields: fireCMSContext.fields
28
+ fields: fireCMSContext.propertyConfigs
29
29
  });
30
30
 
31
31
  if (property?.dataType !== "array")
@@ -25,7 +25,7 @@ export function ArrayPropertyPreview({
25
25
  propertyKey,
26
26
  property: inputProperty,
27
27
  propertyValue: value,
28
- fields: fireCMSContext.fields
28
+ fields: fireCMSContext.propertyConfigs
29
29
  });
30
30
 
31
31
  if (!property.of) {
@@ -86,7 +86,7 @@ export type FireCMSProps<UserType extends User, EC extends EntityCollection> = {
86
86
  * You can use the key to reference the custom field in
87
87
  * the `propertyConfig` prop of a property in a collection.
88
88
  */
89
- fields?: Record<string, PropertyConfig>;
89
+ propertyConfigs?: Record<string, PropertyConfig>;
90
90
 
91
91
  /**
92
92
  * List of additional custom views for entities.
@@ -106,7 +106,7 @@ export type FireCMSContext<UserType extends User = User, AuthControllerType exte
106
106
  * You can use the key to reference the custom field in
107
107
  * the `propertyConfig` prop of a property in a collection.
108
108
  */
109
- fields: Record<string, PropertyConfig>;
109
+ propertyConfigs: Record<string, PropertyConfig>;
110
110
 
111
111
  /**
112
112
  * List of additional custom views for entities.
@@ -117,6 +117,7 @@ export type FireCMSContext<UserType extends User = User, AuthControllerType exte
117
117
  */
118
118
  entityViews?: EntityCustomView[];
119
119
 
120
+
120
121
  components?: {
121
122
 
122
123
  /**
@@ -77,6 +77,7 @@ export type FireCMSPlugin<PROPS = any, FORM_PROPS = any, EC extends EntityCollec
77
77
  homePage?: {
78
78
 
79
79
  additionalChildrenStart?: React.ReactNode;
80
+ additionalChildrenEnd?: React.ReactNode;
80
81
  /**
81
82
  * Use this component to add custom actions to the navigation card
82
83
  * in the home page.
package/src/ui/Select.tsx CHANGED
@@ -179,8 +179,11 @@ export function Select({
179
179
  <SelectPrimitive.Portal>
180
180
  <SelectPrimitive.Content
181
181
  position={position}
182
- className="z-50 overflow-hidden relative border border-gray-200 dark:border-gray-800 bg-white dark:bg-gray-800 p-2 rounded-lg shadow-lg">
183
- <SelectPrimitive.Viewport>
182
+ className="z-50 max-h-[var(--radix-select-content-available-height)] overflow-hidden relative border border-gray-200 dark:border-gray-800 bg-white dark:bg-gray-800 p-2 rounded-lg shadow-lg">
183
+ <SelectPrimitive.Viewport
184
+ className={"p-1 max-h-[var(--radix-select-content-available-height)]"}
185
+ style={{
186
+ }}>
184
187
  {children}
185
188
  </SelectPrimitive.Viewport>
186
189
  </SelectPrimitive.Content>
@@ -255,10 +258,3 @@ export function SelectGroup({
255
258
  {children}
256
259
  </>;
257
260
  }
258
-
259
- function selectOnChangeEventAdapter(fn: (event: React.ChangeEvent<HTMLSelectElement>) => void): (value: string) => void {
260
- return (value: string) => {
261
- const event = { target: { value } } as React.ChangeEvent<HTMLSelectElement>;
262
- fn(event);
263
- };
264
- }
@@ -0,0 +1,138 @@
1
+ import {
2
+ AdditionalFieldDelegate,
3
+ ArrayProperty,
4
+ BooleanProperty,
5
+ CMSType,
6
+ DateProperty,
7
+ EntityCallbacks, EntityCollection,
8
+ EnumValueConfig,
9
+ EnumValues,
10
+ GeopointProperty,
11
+ MapProperty,
12
+ NumberProperty,
13
+ PropertiesOrBuilders,
14
+ PropertyBuilder,
15
+ PropertyConfig,
16
+ PropertyOrBuilder,
17
+ ReferenceProperty,
18
+ StringProperty,
19
+ User
20
+ } from "../types";
21
+
22
+ /**
23
+ * Identity function we use to defeat the type system of Typescript and build
24
+ * collection views with all its properties
25
+ * @param collection
26
+ * @group Builder
27
+ */
28
+ export function buildCollection<M extends Record<string, any> = any,
29
+ UserType extends User = User>(
30
+ collection: EntityCollection<M, UserType>
31
+ ): EntityCollection<M, UserType> {
32
+ return collection;
33
+ }
34
+
35
+ /**
36
+ * Identity function we use to defeat the type system of Typescript and preserve
37
+ * the property keys.
38
+ * @param property
39
+ * @group Builder
40
+ */
41
+ export function buildProperty<T extends CMSType = CMSType, P extends PropertyOrBuilder<T> = PropertyOrBuilder<T>, M extends Record<string, any> = Record<string, any>>(
42
+ property: P
43
+ ):
44
+ P extends StringProperty ? StringProperty :
45
+ P extends NumberProperty ? NumberProperty :
46
+ P extends BooleanProperty ? BooleanProperty :
47
+ P extends DateProperty ? DateProperty :
48
+ P extends GeopointProperty ? GeopointProperty :
49
+ P extends ReferenceProperty ? ReferenceProperty :
50
+ P extends ArrayProperty ? ArrayProperty :
51
+ P extends MapProperty ? MapProperty :
52
+ P extends PropertyBuilder<T, M> ? PropertyBuilder<T, M> : never {
53
+ return property as any;
54
+ }
55
+
56
+ /**
57
+ * Identity function we use to defeat the type system of Typescript and preserve
58
+ * the properties keys.
59
+ * @param properties
60
+ * @group Builder
61
+ */
62
+ export function buildProperties<M extends Record<string, any>>(
63
+ properties: PropertiesOrBuilders<M>
64
+ ): PropertiesOrBuilders<M> {
65
+ return properties;
66
+ }
67
+
68
+ /**
69
+ * Identity function we use to defeat the type system of Typescript and preserve
70
+ * the properties keys.
71
+ * @param propertiesOrBuilder
72
+ * @group Builder
73
+ */
74
+ export function buildPropertiesOrBuilder<M extends Record<string, any>>(
75
+ propertiesOrBuilder: PropertiesOrBuilders<M>
76
+ ): PropertiesOrBuilders<M> {
77
+ return propertiesOrBuilder;
78
+ }
79
+
80
+ /**
81
+ * Identity function we use to defeat the type system of Typescript and preserve
82
+ * the properties keys.
83
+ * @param enumValues
84
+ * @group Builder
85
+ */
86
+ export function buildEnumValues(
87
+ enumValues: EnumValues
88
+ ): EnumValues {
89
+ return enumValues;
90
+ }
91
+
92
+ /**
93
+ * Identity function we use to defeat the type system of Typescript and preserve
94
+ * the properties keys.
95
+ * @param enumValueConfig
96
+ * @group Builder
97
+ */
98
+ export function buildEnumValueConfig(
99
+ enumValueConfig: EnumValueConfig
100
+ ): EnumValueConfig {
101
+ return enumValueConfig;
102
+ }
103
+
104
+ /**
105
+ * Identity function we use to defeat the type system of Typescript and preserve
106
+ * the properties keys.
107
+ * @param callbacks
108
+ * @group Builder
109
+ */
110
+ export function buildEntityCallbacks<M extends Record<string, any> = any>(
111
+ callbacks: EntityCallbacks<M>
112
+ ): EntityCallbacks<M> {
113
+ return callbacks;
114
+ }
115
+
116
+ /**
117
+ * Identity function we use to defeat the type system of Typescript and build
118
+ * additional field delegates views with all its properties
119
+ * @param additionalFieldDelegate
120
+ * @group Builder
121
+ */
122
+ export function buildAdditionalFieldDelegate<M extends Record<string, any>, UserType extends User = User>(
123
+ additionalFieldDelegate: AdditionalFieldDelegate<M, UserType>
124
+ ): AdditionalFieldDelegate<M, UserType> {
125
+ return additionalFieldDelegate;
126
+ }
127
+
128
+ /**
129
+ * Identity function we use to defeat the type system of Typescript and build
130
+ * additional field delegates views with all its properties
131
+ * @param propertyConfig
132
+ * @group Builder
133
+ */
134
+ export function buildFieldConfig<T extends CMSType = CMSType>(
135
+ propertyConfig: PropertyConfig<T>
136
+ ): PropertyConfig<T> {
137
+ return propertyConfig;
138
+ }
package/src/util/index.ts CHANGED
@@ -19,3 +19,4 @@ export * from "./debounce";
19
19
  export * from "./flatten_object";
20
20
  export * from "./make_properties_editable";
21
21
  export * from "./join_collections";
22
+ export * from "./builders";
@@ -143,3 +143,26 @@ export function isEmptyObject(obj: object) {
143
143
  Object.getPrototypeOf(obj) === Object.prototype &&
144
144
  Object.keys(obj).length === 0
145
145
  }
146
+
147
+ export function removePropsIfExisting(source: any, comparison: any) {
148
+ const isObject = (val: any) => typeof val === "object" && val !== null;
149
+ const isArray = (val: any) => Array.isArray(val);
150
+
151
+ if (!isObject(source) || !isObject(comparison)) {
152
+ return source;
153
+ }
154
+
155
+ const res = isArray(source) ? [...source] : { ...source };
156
+
157
+ Object.keys(comparison).forEach(key => {
158
+ if (key in res) {
159
+ if (isObject(res[key]) && isObject(comparison[key])) {
160
+ res[key] = removePropsIfExisting(res[key], comparison[key]);
161
+ } else if (res[key] === comparison[key]) {
162
+ isArray(res) ? res.splice(key, 1) : delete res[key];
163
+ }
164
+ }
165
+ });
166
+
167
+ return res;
168
+ }
@@ -180,11 +180,14 @@ export function resolveProperty<T extends CMSType = CMSType, M extends Record<st
180
180
  if (resolvedProperty.propertyConfig && !isDefaultFieldConfigId(resolvedProperty.propertyConfig)) {
181
181
  const cmsFields = props.fields;
182
182
  if (!cmsFields) {
183
- throw Error(`Trying to resolve a property with key ${resolvedProperty.propertyConfig} that inherits from a custom field but no custom fields were provided. Use the property 'fields' in your top level component to provide them`);
183
+ throw Error(`Trying to resolve a property with key ${resolvedProperty.propertyConfig} that inherits from a custom property config but no custom property configs were provided. Use the property \`propertyConfigs\` in your app config to provide them`);
184
184
  }
185
185
  const customField: PropertyConfig<any> = cmsFields[resolvedProperty.propertyConfig];
186
- if (!customField)
187
- throw Error(`Trying to resolve a property that inherits from a custom field but no custom field with id ${resolvedProperty.propertyConfig} was found. Check the \`fields\` in your top level component`);
186
+ if (!customField) {
187
+ console.warn(`Trying to resolve a property with key ${resolvedProperty.propertyConfig} that inherits from a custom property config but no custom property config with that key was found. Check the \`propertyConfigs\` in your app config`)
188
+ console.warn("Available property configs", cmsFields);
189
+ return null;
190
+ }
188
191
  if (customField.property) {
189
192
  const configPropertyOrBuilder = customField.property;
190
193
  if ("propertyConfig" in configPropertyOrBuilder) {