@firecms/core 3.0.0-alpha.26 → 3.0.0-alpha.28

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 (51) hide show
  1. package/dist/components/Popover.d.ts +3 -1
  2. package/dist/core/builders.d.ts +3 -3
  3. package/dist/core/components/EntityCollectionTable/filters/ReferenceFilterField.d.ts +3 -3
  4. package/dist/core/components/FieldConfigBadge.d.ts +3 -3
  5. package/dist/core/components/VirtualTable/VirtualTableHeader.d.ts +2 -2
  6. package/dist/core/form_field_configs.d.ts +3 -3
  7. package/dist/core/util/property_utils.d.ts +5 -5
  8. package/dist/core/util/references.d.ts +2 -2
  9. package/dist/core/util/resolutions.d.ts +5 -5
  10. package/dist/hooks/index.d.ts +1 -0
  11. package/dist/hooks/useBuildDataSource.d.ts +23 -0
  12. package/dist/index.es.js +6877 -6634
  13. package/dist/index.es.js.map +1 -1
  14. package/dist/index.umd.js +14 -14
  15. package/dist/index.umd.js.map +1 -1
  16. package/dist/types/datasource.d.ts +120 -11
  17. package/dist/types/fields.d.ts +1 -1
  18. package/dist/types/firecms.d.ts +3 -3
  19. package/dist/types/firecms_context.d.ts +3 -3
  20. package/dist/types/index.d.ts +1 -1
  21. package/dist/types/properties.d.ts +1 -1
  22. package/dist/types/{field_config.d.ts → property_config.d.ts} +3 -4
  23. package/package.json +2 -2
  24. package/src/components/Popover.tsx +10 -3
  25. package/src/components/TextareaAutosize.tsx +2 -1
  26. package/src/core/builders.ts +5 -5
  27. package/src/core/components/EntityCollectionTable/EntityCollectionTable.tsx +4 -4
  28. package/src/core/components/EntityCollectionTable/filters/ReferenceFilterField.tsx +11 -6
  29. package/src/core/components/EntityCollectionTable/internal/PropertyTableCell.tsx +2 -2
  30. package/src/core/components/EntityCollectionTable/internal/popup_field/PopupFormField.tsx +6 -2
  31. package/src/core/components/EntityCollectionView/EntityCollectionView.tsx +1 -1
  32. package/src/core/components/FieldConfigBadge.tsx +4 -4
  33. package/src/core/components/VirtualTable/VirtualTableHeader.tsx +21 -18
  34. package/src/core/form_field_configs.tsx +5 -5
  35. package/src/core/util/property_utils.tsx +5 -5
  36. package/src/core/util/references.ts +2 -2
  37. package/src/core/util/resolutions.ts +16 -11
  38. package/src/form/EntityForm.tsx +1 -1
  39. package/src/form/PropertyFieldBinding.tsx +4 -4
  40. package/src/form/field_bindings/KeyValueFieldBinding.tsx +1 -1
  41. package/src/form/field_bindings/ReadOnlyFieldBinding.tsx +4 -6
  42. package/src/hooks/index.tsx +1 -0
  43. package/src/hooks/useBuildDataSource.ts +351 -0
  44. package/src/preview/property_previews/StringPropertyPreview.tsx +4 -2
  45. package/src/types/datasource.ts +174 -10
  46. package/src/types/fields.tsx +1 -1
  47. package/src/types/firecms.tsx +3 -3
  48. package/src/types/firecms_context.tsx +3 -3
  49. package/src/types/index.ts +1 -1
  50. package/src/types/properties.ts +1 -1
  51. package/src/types/{field_config.tsx → property_config.tsx} +3 -4
@@ -1,13 +1,13 @@
1
1
  import React from "react";
2
2
 
3
- import { EntityCollection, FieldConfig, PropertiesOrBuilders, PropertyOrBuilder, ResolvedProperty } from "../../types";
3
+ import { EntityCollection, PropertyConfig, PropertiesOrBuilders, PropertyOrBuilder, ResolvedProperty } from "../../types";
4
4
  import { getFieldConfig } from "../form_field_configs";
5
5
  import { isPropertyBuilder } from "./entities";
6
6
  import { resolveProperty } from "./resolutions";
7
7
  import { CircleIcon, FunctionsIcon } from "../../icons";
8
8
 
9
9
  export function isReferenceProperty(propertyOrBuilder: PropertyOrBuilder,
10
- fields: Record<string, FieldConfig>) {
10
+ fields: Record<string, PropertyConfig>) {
11
11
  const resolvedProperty = resolveProperty({
12
12
  propertyKey: "ignore", // TODO
13
13
  propertyOrBuilder,
@@ -28,7 +28,7 @@ export function getIdIcon(size: "small" | "medium" | "large"): React.ReactNode {
28
28
  return <CircleIcon size={size}/>;
29
29
  }
30
30
 
31
- export function getIconForWidget(widget: FieldConfig | undefined,
31
+ export function getIconForWidget(widget: PropertyConfig | undefined,
32
32
  size: "small" | "medium" | "large") {
33
33
  const Icon = widget?.Icon ?? CircleIcon;
34
34
  return <Icon size={size}/>;
@@ -37,7 +37,7 @@ export function getIconForWidget(widget: FieldConfig | undefined,
37
37
  export function getIconForProperty(
38
38
  property: PropertyOrBuilder | ResolvedProperty,
39
39
  size: "small" | "medium" | "large" = "small",
40
- fields: Record<string, FieldConfig> = {}
40
+ fields: Record<string, PropertyConfig> = {}
41
41
  ): React.ReactNode {
42
42
 
43
43
  if (isPropertyBuilder(property)) {
@@ -48,7 +48,7 @@ export function getIconForProperty(
48
48
  }
49
49
  }
50
50
 
51
- export function getColorForProperty(property: PropertyOrBuilder, fields: Record<string, FieldConfig>): string {
51
+ export function getColorForProperty(property: PropertyOrBuilder, fields: Record<string, PropertyConfig>): string {
52
52
  if (isPropertyBuilder(property)) {
53
53
  return "#888";
54
54
  } else {
@@ -1,9 +1,9 @@
1
- import { EntityCollection, FieldConfig } from "../../types";
1
+ import { EntityCollection, PropertyConfig } from "../../types";
2
2
  import { isReferenceProperty } from "./property_utils";
3
3
  import { isPropertyBuilder } from "./entities";
4
4
 
5
5
  export function getReferencePreviewKeys(targetCollection: EntityCollection<any>,
6
- fields: Record<string, FieldConfig>,
6
+ fields: Record<string, PropertyConfig>,
7
7
  previewProperties?: string[],
8
8
  limit = 3) {
9
9
  const allProperties = Object.keys(targetCollection.properties);
@@ -1,11 +1,12 @@
1
1
  import {
2
2
  ArrayProperty,
3
3
  CMSType,
4
- EntityCollection, EntityCustomView,
4
+ EntityCollection,
5
+ EntityCustomView,
5
6
  EntityValues,
6
7
  EnumValueConfig,
7
8
  EnumValues,
8
- FieldConfig,
9
+ PropertyConfig,
9
10
  NumberProperty,
10
11
  Properties,
11
12
  PropertiesOrBuilders,
@@ -43,7 +44,7 @@ export const resolveCollection = <M extends Record<string, any>, >
43
44
  values?: Partial<EntityValues<M>>,
44
45
  previousValues?: Partial<EntityValues<M>>,
45
46
  userConfigPersistence?: UserConfigurationPersistence;
46
- fields?: Record<string, FieldConfig>;
47
+ fields?: Record<string, PropertyConfig>;
47
48
  }): ResolvedEntityCollection<M> => {
48
49
 
49
50
  const collectionOverride = userConfigPersistence?.getCollectionConfig<M>(path);
@@ -107,7 +108,7 @@ export function resolveProperty<T extends CMSType = CMSType, M extends Record<st
107
108
  entityId?: string,
108
109
  index?: number,
109
110
  fromBuilder?: boolean;
110
- fields?: Record<string, FieldConfig<any>>;
111
+ fields?: Record<string, PropertyConfig<any>>;
111
112
  }): ResolvedProperty<T> | null {
112
113
 
113
114
  if (typeof propertyOrBuilder === "object" && "resolved" in propertyOrBuilder) {
@@ -176,17 +177,21 @@ export function resolveProperty<T extends CMSType = CMSType, M extends Record<st
176
177
  } as ResolvedProperty<T>;
177
178
  }
178
179
 
179
- if (resolvedProperty.fieldConfig && !isDefaultFieldConfigId(resolvedProperty.fieldConfig)) {
180
+ if (resolvedProperty.propertyConfig && !isDefaultFieldConfigId(resolvedProperty.propertyConfig)) {
180
181
  const cmsFields = props.fields;
181
182
  if (!cmsFields) {
182
- throw Error(`Trying to resolve a property with key ${resolvedProperty.fieldConfig} 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 field but no custom fields were provided. Use the property 'fields' in your top level component to provide them`);
183
184
  }
184
- const customField: FieldConfig<any> = cmsFields[resolvedProperty.fieldConfig];
185
+ const customField: PropertyConfig<any> = cmsFields[resolvedProperty.propertyConfig];
185
186
  if (!customField)
186
- throw Error(`Trying to resolve a property that inherits from a custom field but no custom field with id ${resolvedProperty.fieldConfig} was found. Check the \`fields\` in your top level component`);
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`);
187
188
  if (customField.property) {
189
+ const configPropertyOrBuilder = customField.property;
190
+ if ("propertyConfig" in configPropertyOrBuilder) {
191
+ delete configPropertyOrBuilder.propertyConfig;
192
+ }
188
193
  const customFieldProperty = resolveProperty<any>({
189
- propertyOrBuilder: customField.property,
194
+ propertyOrBuilder: configPropertyOrBuilder,
190
195
  propertyValue,
191
196
  ...props
192
197
  });
@@ -220,7 +225,7 @@ export function resolveArrayProperty<T extends any[], M>({
220
225
  entityId?: string,
221
226
  index?: number,
222
227
  fromBuilder?: boolean;
223
- fields?: Record<string, FieldConfig>;
228
+ fields?: Record<string, PropertyConfig>;
224
229
  }): ResolvedArrayProperty {
225
230
 
226
231
  if (property.of) {
@@ -326,7 +331,7 @@ export function resolveProperties<M extends Record<string, any>>({
326
331
  entityId?: string,
327
332
  index?: number,
328
333
  fromBuilder?: boolean;
329
- fields?: Record<string, FieldConfig>;
334
+ fields?: Record<string, PropertyConfig>;
330
335
  }): ResolvedProperties<M> {
331
336
  return Object.entries<PropertyOrBuilder>(properties as Record<string, PropertyOrBuilder>)
332
337
  .map(([key, property]) => {
@@ -315,7 +315,7 @@ function EntityFormInternal<M extends Record<string, any>>({
315
315
  name,
316
316
  value,
317
317
  property
318
- }) => dataSource.checkUniqueField(path, name, value, property, entityId),
318
+ }) => dataSource.checkUniqueField(path, name, value, entityId),
319
319
  [dataSource, path, entityId]);
320
320
 
321
321
  const validationSchema = useMemo(() => entityId
@@ -121,13 +121,13 @@ function PropertyFieldBindingInternal<T extends CMSType = CMSType, CustomProps =
121
121
  Component = resolvedProperty.Field as ComponentType<FieldProps<any>>;
122
122
  }
123
123
  } else {
124
- const fieldConfig = getFieldConfig(resolvedProperty, fireCMSContext.fields);
125
- if (!fieldConfig) {
126
- console.log("INTERNAL: Could not find field config for property", { propertyKey, resolvedProperty, fields: fireCMSContext.fields, fieldConfig });
124
+ const propertyConfig = getFieldConfig(resolvedProperty, fireCMSContext.fields);
125
+ if (!propertyConfig) {
126
+ console.log("INTERNAL: Could not find field config for property", { propertyKey, resolvedProperty, fields: fireCMSContext.fields, propertyConfig });
127
127
  throw new Error(`INTERNAL: Could not find field config for property ${propertyKey}`);
128
128
  }
129
129
  const configProperty = resolveProperty({
130
- propertyOrBuilder: fieldConfig.property,
130
+ propertyOrBuilder: propertyConfig.property,
131
131
  propertyValue: fieldProps.field.value,
132
132
  values: fieldProps.form.values,
133
133
  path: context.path,
@@ -164,7 +164,7 @@ function MapEditView<T extends Record<string, any>>({
164
164
  }
165
165
 
166
166
  const newValue = { ...(value ?? {}) } as T;
167
- if (originalValue.current && fieldKey in originalValue.current) {
167
+ if (typeof originalValue.current === "object" && fieldKey in originalValue.current) {
168
168
  // @ts-ignore
169
169
  newValue[fieldKey] = undefined; // set to undefined to remove from the object, the datasource will remove it from the backend
170
170
  } else {
@@ -3,12 +3,10 @@ import React from "react";
3
3
  import { Entity, FieldProps } from "../../types";
4
4
 
5
5
  import { PropertyPreview } from "../../preview";
6
- import { LabelWithIcon } from "../components";
7
- import { ErrorBoundary } from "../../core/components/ErrorBoundary";
8
- import { getIconForProperty } from "../../core";
6
+ import { FieldHelperText, LabelWithIcon } from "../components";
7
+ import { ErrorBoundary, getIconForProperty } from "../../core";
9
8
  import { paperMixin } from "../../styles";
10
- import { FieldHelperText } from "../components/FieldHelperText";
11
- import { cn } from "../../components/util/cn";
9
+ import { cn } from "../../components";
12
10
 
13
11
  /**
14
12
  *
@@ -49,7 +47,7 @@ export function ReadOnlyFieldBinding({
49
47
  }
50
48
 
51
49
  <div
52
- className={cn(paperMixin, "min-h-14 p-4 md:p-6")}>
50
+ className={cn(paperMixin, "min-h-14 p-4 md:p-6 overflow-x-scroll no-scrollbar")}>
53
51
 
54
52
  <ErrorBoundary>
55
53
  <PropertyPreview propertyKey={propertyKey}
@@ -22,3 +22,4 @@ export * from "./useLargeLayout";
22
22
 
23
23
  export * from "./useReferenceDialog";
24
24
  export * from "./useBrowserTitleAndIcon";
25
+ export * from "./useBuildDataSource";
@@ -0,0 +1,351 @@
1
+ import { useCallback } from "react";
2
+ import {
3
+ DataSource,
4
+ DataSourceDelegate, DeleteEntityProps,
5
+ Entity,
6
+ EntityCollection,
7
+ EntityReference,
8
+ EntityValues,
9
+ FetchCollectionProps,
10
+ FetchEntityProps,
11
+ FilterValues,
12
+ GeoPoint,
13
+ ListenCollectionProps,
14
+ ListenEntityProps,
15
+ PropertyConfig,
16
+ ResolvedProperties,
17
+ SaveEntityProps
18
+ } from "../types";
19
+ import { resolveCollection, updateDateAutoValues } from "../core";
20
+
21
+ /**
22
+ * Use this hook to build a {@link DataSource} based on Firestore
23
+ * @param firebaseApp
24
+ * @param textSearchController
25
+ * @param collectionRegistry
26
+ * @category Firebase
27
+ */
28
+ export function useBuildDataSource({
29
+ delegate,
30
+ customFields
31
+ }: {
32
+ delegate: DataSourceDelegate,
33
+ customFields: Record<string, PropertyConfig>;
34
+ }): DataSource {
35
+
36
+ return {
37
+
38
+ /**
39
+ * Fetch entities in a Firestore path
40
+ * @param path
41
+ * @param collection
42
+ * @param filter
43
+ * @param limit
44
+ * @param startAfter
45
+ * @param searchString
46
+ * @param orderBy
47
+ * @param order
48
+ * @return Function to cancel subscription
49
+ * @see useCollectionFetch if you need this functionality implemented as a hook
50
+ * @category Firestore
51
+ */
52
+ fetchCollection: useCallback(<M extends Record<string, any>>({
53
+ path,
54
+ collection,
55
+ filter,
56
+ limit,
57
+ startAfter,
58
+ searchString,
59
+ orderBy,
60
+ order
61
+ }: FetchCollectionProps<M>
62
+ ): Promise<Entity<M>[]> => {
63
+
64
+ return delegate.fetchCollection<M>({
65
+ path,
66
+ filter,
67
+ limit,
68
+ startAfter,
69
+ searchString,
70
+ orderBy,
71
+ order
72
+ });
73
+ }, [delegate]),
74
+
75
+ /**
76
+ * Listen to a entities in a given path
77
+ * @param path
78
+ * @param collection
79
+ * @param onError
80
+ * @param filter
81
+ * @param limit
82
+ * @param startAfter
83
+ * @param searchString
84
+ * @param orderBy
85
+ * @param order
86
+ * @param onUpdate
87
+ * @return Function to cancel subscription
88
+ * @see useCollectionFetch if you need this functionality implemented as a hook
89
+ * @category Firestore
90
+ */
91
+ listenCollection: delegate.listenCollection
92
+ // eslint-disable-next-line react-hooks/rules-of-hooks
93
+ ? useCallback(<M extends Record<string, any>>(
94
+ {
95
+ path,
96
+ collection,
97
+ filter,
98
+ limit,
99
+ startAfter,
100
+ searchString,
101
+ orderBy,
102
+ order,
103
+ onUpdate,
104
+ onError
105
+ }: ListenCollectionProps<M>
106
+ ): () => void => {
107
+
108
+ const isCollectionGroup = Boolean(collection.collectionGroup) ?? false;
109
+ if (!delegate.listenCollection)
110
+ throw Error("useBuildDataSource delegate not initialised");
111
+
112
+ return delegate.listenCollection<M>({
113
+ path,
114
+ filter,
115
+ limit,
116
+ startAfter,
117
+ searchString,
118
+ orderBy,
119
+ order,
120
+ onUpdate,
121
+ onError,
122
+ isCollectionGroup
123
+ });
124
+ }, [delegate])
125
+ : undefined,
126
+
127
+ /**
128
+ * Retrieve an entity given a path and a collection
129
+ * @param path
130
+ * @param entityId
131
+ * @param collection
132
+ * @category Firestore
133
+ */
134
+ fetchEntity: useCallback(<M extends Record<string, any>>({
135
+ path,
136
+ entityId
137
+ }: FetchEntityProps<M>
138
+ ): Promise<Entity<M> | undefined> => delegate.fetchEntity({
139
+ path,
140
+ entityId
141
+ }), [delegate]),
142
+
143
+ /**
144
+ *
145
+ * @param path
146
+ * @param entityId
147
+ * @param collection
148
+ * @param onUpdate
149
+ * @param onError
150
+ * @return Function to cancel subscription
151
+ * @category Firestore
152
+ */
153
+ listenEntity: delegate.listenEntity
154
+ // eslint-disable-next-line react-hooks/rules-of-hooks
155
+ ? useCallback(<M extends Record<string, any>>(
156
+ {
157
+ path,
158
+ entityId,
159
+ collection,
160
+ onUpdate,
161
+ onError
162
+ }: ListenEntityProps<M>): () => void => {
163
+ if (!delegate.listenEntity)
164
+ throw Error("useBuildDataSource delegate not initialised");
165
+
166
+ return delegate.listenEntity<M>({
167
+ path,
168
+ entityId,
169
+ onUpdate,
170
+ onError
171
+ })
172
+ }, [delegate.listenEntity]) : undefined,
173
+
174
+ /**
175
+ * Save entity to the specified path. Note that Firestore does not allow
176
+ * undefined values.
177
+ * @param path
178
+ * @param entityId
179
+ * @param values
180
+ * @param schemaId
181
+ * @param collection
182
+ * @param status
183
+ * @category Firestore
184
+ */
185
+ saveEntity: useCallback(<M extends Record<string, any>>(
186
+ {
187
+ path,
188
+ entityId,
189
+ values,
190
+ collection,
191
+ status
192
+ }: SaveEntityProps<M>): Promise<Entity<M>> => {
193
+
194
+ const resolvedCollection = resolveCollection<M>({
195
+ collection,
196
+ path,
197
+ entityId,
198
+ fields: customFields
199
+ });
200
+
201
+ const properties: ResolvedProperties<M> = resolvedCollection.properties;
202
+
203
+ const firestoreValues = cmsToDelegateModel(
204
+ values,
205
+ delegate.buildReference,
206
+ delegate.buildGeoPoint,
207
+ delegate.buildDate,
208
+ delegate.buildDeleteFieldValue
209
+ );
210
+ const updatedFirestoreValues: EntityValues<M> = updateDateAutoValues(
211
+ {
212
+ inputValues: firestoreValues,
213
+ properties,
214
+ status,
215
+ timestampNowValue: delegate.currentTime(),
216
+ setDateToMidnight: delegate.setDateToMidnight
217
+ });
218
+
219
+ console.debug("Saving entity", path, entityId, updatedFirestoreValues);
220
+
221
+ return delegate.saveEntity({
222
+ path,
223
+ entityId,
224
+ values: updatedFirestoreValues,
225
+ status
226
+ }).then((res) => {
227
+ return {
228
+ id: res.id,
229
+ path: res.path,
230
+ values: delegate.delegateToCMSModel(updatedFirestoreValues)
231
+ } as Entity<M>;
232
+ });
233
+ }, [delegate.saveEntity]),
234
+
235
+ /**
236
+ * Delete an entity
237
+ * @param entity
238
+ * @param collection
239
+ * @category Firestore
240
+ */
241
+ deleteEntity: useCallback(<M extends Record<string, any>>(
242
+ {
243
+ entity
244
+ }: DeleteEntityProps<M>
245
+ ): Promise<void> => {
246
+ return delegate.deleteEntity({entity});
247
+ }, [delegate.deleteEntity]),
248
+
249
+ /**
250
+ * Check if the given property is unique in the given collection
251
+ * @param path Collection path
252
+ * @param name of the property
253
+ * @param value
254
+ * @param property
255
+ * @param entityId
256
+ * @return `true` if there are no other fields besides the given entity
257
+ * @category Firestore
258
+ */
259
+ checkUniqueField: useCallback((
260
+ path: string,
261
+ name: string,
262
+ value: any,
263
+ entityId?: string
264
+ ): Promise<boolean> => {
265
+ return delegate.checkUniqueField(path, name, value, entityId);
266
+ }, [delegate.checkUniqueField]),
267
+
268
+ generateEntityId: useCallback((path: string): string => {
269
+ return delegate.generateEntityId(path, );
270
+ }, [delegate.generateEntityId]),
271
+
272
+ countEntities: useCallback(async ({
273
+ path,
274
+ collection,
275
+ filter,
276
+ order,
277
+ orderBy
278
+ }: {
279
+ path: string,
280
+ collection: EntityCollection<any>,
281
+ filter?: FilterValues<Extract<keyof any, string>>,
282
+ orderBy?: string,
283
+ order?: "desc" | "asc",
284
+ }): Promise<number> => {
285
+ return delegate.countEntities({
286
+ path,
287
+ filter,
288
+ orderBy,
289
+ order,
290
+ isCollectionGroup: Boolean(collection.collectionGroup) ?? false
291
+ });
292
+ }, [delegate.countEntities]),
293
+
294
+ isFilterCombinationValid: useCallback(({
295
+ path,
296
+ filterValues,
297
+ sortBy
298
+ }: {
299
+ path: string,
300
+ filterValues: FilterValues<any>,
301
+ sortBy?: [string, "asc" | "desc"]
302
+ }): boolean => {
303
+ if (!delegate.isFilterCombinationValid)
304
+ return true;
305
+ return delegate.isFilterCombinationValid(
306
+ {
307
+ path,
308
+ filterValues,
309
+ sortBy
310
+ }
311
+ )
312
+ }, [delegate.isFilterCombinationValid])
313
+
314
+ };
315
+
316
+ }
317
+
318
+ /**
319
+ * Recursive function that converts Firestore data types into CMS or plain
320
+ * JS types.
321
+ * FireCMS uses Javascript dates internally instead of Firestore timestamps.
322
+ * This makes it easier to interact with the rest of the libraries and
323
+ * bindings.
324
+ * Also, Firestore references are replaced with {@link EntityReference}
325
+ * @param data
326
+ * @category Firestore
327
+ */
328
+ export function cmsToDelegateModel(data: any,
329
+ buildReference: (reference: EntityReference) => any,
330
+ buildGeoPoint: (geoPoint: GeoPoint) => any,
331
+ buildDate: (date: Date) => any,
332
+ buildDelete: () => any
333
+ ): any {
334
+ if (data === undefined) {
335
+ return buildDelete();
336
+ } else if (Array.isArray(data)) {
337
+ return data.map(v => cmsToDelegateModel(v, buildReference, buildGeoPoint, buildDate, buildDelete));
338
+ } else if (data instanceof EntityReference) {
339
+ return buildReference(data);
340
+ } else if (data instanceof GeoPoint) {
341
+ return buildGeoPoint(data);
342
+ } else if (data instanceof Date) {
343
+ return buildDate(data);
344
+ } else if (data && typeof data === "object") {
345
+ return Object.entries(data)
346
+ .map(([key, v]) => ({ [key]: cmsToDelegateModel(v, buildReference, buildGeoPoint, buildDate, buildDelete) }))
347
+ .reduce((a, b) => ({ ...a, ...b }), {});
348
+ }
349
+ return data;
350
+ }
351
+
@@ -45,13 +45,15 @@ export function StringPropertyPreview({
45
45
  if (!value) return <></>;
46
46
  const lines = value.split("\n");
47
47
  return value && value.includes("\n")
48
- ? <div>
48
+ ? <div className={"overflow-x-scroll"}>
49
49
  {lines.map((str, index) =>
50
50
  <React.Fragment key={`string_preview_${index}`}>
51
51
  <span>{str}</span>
52
52
  {index !== lines.length - 1 && <br/>}
53
53
  </React.Fragment>)}
54
54
  </div>
55
- : <>{value}</>;
55
+ : <>
56
+ {value}
57
+ </>;
56
58
  }
57
59
  }