@firecms/collection_editor 3.0.0-rc.1 → 3.0.0-rc.3

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.
@@ -2,4 +2,4 @@ import { EntityCollection } from "@firecms/core";
2
2
  /**
3
3
  * This function is used to infer the configuration of a collection given its path.
4
4
  */
5
- export type CollectionInference = (path: string, collectionGroup: boolean, parentCollectionPaths: string[]) => Promise<Partial<EntityCollection> | null>;
5
+ export type CollectionInference = (path: string, collectionGroup: boolean, parentCollectionPaths: string[], databaseId?: string) => Promise<Partial<EntityCollection> | null>;
@@ -1,5 +1,5 @@
1
1
  export declare function StringPropertyField({ widgetId, disabled, showErrors }: {
2
- widgetId: "text_field" | "multiline" | "email";
2
+ widgetId: "text_field" | "multiline" | "email" | "user_select";
3
3
  disabled: boolean;
4
4
  showErrors: boolean;
5
5
  }): import("react/jsx-runtime").JSX.Element;
@@ -1,3 +1,3 @@
1
1
  import { Properties, PropertiesOrBuilders, PropertyOrBuilder } from "@firecms/core";
2
- export declare function editableProperty(property: PropertyOrBuilder | PropertyOrBuilder): boolean;
2
+ export declare function editableProperty(property: PropertyOrBuilder): boolean;
3
3
  export declare function removeNonEditableProperties(properties: PropertiesOrBuilders<any>): Properties;
package/package.json CHANGED
@@ -1,18 +1,18 @@
1
1
  {
2
2
  "name": "@firecms/collection_editor",
3
3
  "type": "module",
4
- "version": "3.0.0-rc.1",
4
+ "version": "3.0.0-rc.3",
5
5
  "main": "./dist/index.umd.js",
6
6
  "module": "./dist/index.es.js",
7
7
  "types": "./dist/index.d.ts",
8
8
  "source": "src/index.ts",
9
9
  "dependencies": {
10
- "@firecms/data_export": "^3.0.0-rc.1",
11
- "@firecms/data_import": "^3.0.0-rc.1",
12
- "@firecms/data_import_export": "^3.0.0-rc.1",
13
- "@firecms/formex": "^3.0.0-rc.1",
14
- "@firecms/schema_inference": "^3.0.0-rc.1",
15
- "@firecms/ui": "^3.0.0-rc.1",
10
+ "@firecms/data_export": "^3.0.0-rc.3",
11
+ "@firecms/data_import": "^3.0.0-rc.3",
12
+ "@firecms/data_import_export": "^3.0.0-rc.3",
13
+ "@firecms/formex": "^3.0.0-rc.3",
14
+ "@firecms/schema_inference": "^3.0.0-rc.3",
15
+ "@firecms/ui": "^3.0.0-rc.3",
16
16
  "json5": "^2.2.3",
17
17
  "prism-react-renderer": "^2.4.1"
18
18
  },
@@ -69,5 +69,5 @@
69
69
  "publishConfig": {
70
70
  "access": "public"
71
71
  },
72
- "gitHead": "e91ae67d24262a9b944550abaae626f182688aa1"
72
+ "gitHead": "213f4c106eb3e6639eb1ad23c7d94282ef54d444"
73
73
  }
@@ -49,7 +49,7 @@ export interface ConfigControllerProviderProps {
49
49
  icon: React.ReactNode
50
50
  };
51
51
 
52
- getUser?: (uid: string) => User | null
52
+ getUser?: (uid: string) => User | null;
53
53
 
54
54
  getData?: (path: string, parentPaths: string[]) => Promise<object[]>;
55
55
 
@@ -174,7 +174,7 @@ export const ConfigControllerProvider = React.memo(
174
174
  currentPropertiesOrder,
175
175
  editedCollectionId,
176
176
  parentCollectionIds,
177
- collectionEditable: collection?.editable ?? false,
177
+ collectionEditable: collection?.editable === undefined || collection?.editable === true,
178
178
  existingEntities
179
179
  });
180
180
  };
@@ -3,4 +3,4 @@ import { EntityCollection } from "@firecms/core";
3
3
  /**
4
4
  * This function is used to infer the configuration of a collection given its path.
5
5
  */
6
- export type CollectionInference = (path: string, collectionGroup: boolean, parentCollectionPaths: string[]) => Promise<Partial<EntityCollection> | null>;
6
+ export type CollectionInference = (path: string, collectionGroup: boolean, parentCollectionPaths: string[], databaseId?:string) => Promise<Partial<EntityCollection> | null>;
@@ -356,6 +356,19 @@ export function CollectionDetailsForm({
356
356
  </FieldCaption>
357
357
  </div>
358
358
 
359
+ <div className={"col-span-12"}>
360
+ <BooleanSwitchWithLabel
361
+ position={"start"}
362
+ size={"large"}
363
+ label={values.inlineEditing === undefined || values.inlineEditing ? "Data can be edited directly in the table view" : "Data can be edited only in the form view"}
364
+ onValueChange={(v) => setFieldValue("inlineEditing", v)}
365
+ value={values.inlineEditing === undefined ? true : values.inlineEditing}
366
+ />
367
+ <FieldCaption>
368
+ Allow editing data directly in the table view, without opening the form view.
369
+ </FieldCaption>
370
+ </div>
371
+
359
372
  <div className={"col-span-12"}>
360
373
  <Select
361
374
  name="customId"
@@ -329,7 +329,7 @@ function CollectionEditorInternal<M extends Record<string, any>>({
329
329
 
330
330
  const doCollectionInference = collectionInference ? (collection: PersistedCollection<any>) => {
331
331
  if (!collectionInference) return undefined;
332
- return collectionInference?.(collection.path, collection.collectionGroup ?? false, parentPaths ?? []);
332
+ return collectionInference?.(collection.path, collection.collectionGroup ?? false, parentPaths ?? [], collection.databaseId);
333
333
  } : undefined;
334
334
 
335
335
  const inferCollectionFromData = async (newCollection: PersistedCollection<M>) => {
@@ -255,14 +255,6 @@ export function CollectionPropertiesEditorForm({
255
255
  setFieldTouched(previousPropertyPath, false, false);
256
256
  }
257
257
 
258
- console.debug("onPropertyChanged", {
259
- id,
260
- property,
261
- previousId,
262
- namespace,
263
- propertyPath
264
- })
265
-
266
258
  if (propertyPath) {
267
259
  setFieldValue(propertyPath, property, false);
268
260
  setFieldTouched(propertyPath, true, false);
@@ -119,7 +119,7 @@ export const PropertyForm = React.memo(
119
119
  name: ""
120
120
  } as PropertyWithId;
121
121
 
122
- const disabled = (Boolean(property && !editableProperty(property)) && !collectionEditable);
122
+ const disabled = (Boolean(property && !editableProperty(property)) || !collectionEditable);
123
123
 
124
124
  const lastSubmittedProperty = useRef<OnPropertyChangedParams | undefined>(property ? {
125
125
  id: propertyKey,
@@ -150,7 +150,6 @@ export const PropertyForm = React.memo(
150
150
  validateOnChange: true,
151
151
  validateOnInitialRender: true,
152
152
  onSubmit: (newPropertyWithId, controller) => {
153
- console.debug("onSubmit", newPropertyWithId);
154
153
  const {
155
154
  id,
156
155
  ...property
@@ -401,6 +400,7 @@ function PropertyEditFormFields({
401
400
  let childComponent;
402
401
  if (selectedFieldConfigId === "text_field" ||
403
402
  selectedFieldConfigId === "multiline" ||
403
+ selectedFieldConfigId === "user_select" ||
404
404
  selectedFieldConfigId === "email") {
405
405
  childComponent =
406
406
  <StringPropertyField widgetId={selectedFieldConfigId}
@@ -499,7 +499,7 @@ function PropertyEditFormFields({
499
499
  <Typography>This property can&apos;t be edited</Typography>
500
500
  <Typography variant={"caption"}>
501
501
  You may not have permission to
502
- edit it or it is defined in code with no <code>editable</code> flag
502
+ edit it or it is defined in code with the <code>editable</code> flag set to <code>false</code>.
503
503
  </Typography>
504
504
  </InfoLabel>}
505
505
 
@@ -605,6 +605,7 @@ const WIDGET_TYPE_MAP: Record<PropertyConfigId, string> = {
605
605
  url: "Text",
606
606
  email: "Text",
607
607
  switch: "Boolean",
608
+ user_select: "Users",
608
609
  select: "Select",
609
610
  multi_select: "Select",
610
611
  number_input: "Number",
@@ -786,6 +787,7 @@ export function WidgetSelectViewItem({
786
787
  <WarningIcon size="smallest" className={"w-4"}/>
787
788
  </Tooltip>}
788
789
  <Typography
790
+ variant={"label"}
789
791
  color={shouldWarnChangingDataType ? "secondary" : undefined}>{propertyConfig.name}</Typography>
790
792
  </div>
791
793
 
@@ -69,7 +69,7 @@ export function PropertyFieldPreview({
69
69
 
70
70
  {includeName &&
71
71
  <ErrorBoundary>
72
- <Typography variant="body1"
72
+ <Typography variant="label"
73
73
  component="span"
74
74
  className="flex-grow pr-2">
75
75
  {property.name
@@ -82,7 +82,7 @@ export function PropertyFieldPreview({
82
82
  <div className="flex flex-row items-center">
83
83
  <ErrorBoundary>
84
84
  <Typography className="flex-grow pr-2"
85
- variant={includeName ? "body2" : "subtitle1"}
85
+ variant={includeName ? "body2" : "label"}
86
86
  component="span"
87
87
  color="secondary">
88
88
  {propertyConfig?.name}
@@ -131,8 +131,8 @@ export function NonEditablePropertyPreview({
131
131
  <div className={"relative m-4"}>
132
132
  {propertyConfig && <PropertyConfigBadge propertyConfig={propertyConfig}/>}
133
133
  {!propertyConfig && <div
134
- className={"h-8 w-8 p-1 rounded-full shadow text-white bg-surface-500"}>
135
- <FunctionsIcon color={"inherit"} size={"medium"}/>
134
+ className={"h-8 w-8 flex items-center justify-center rounded-full shadow text-white bg-surface-500"}>
135
+ <FunctionsIcon color={"inherit"} size={"small"}/>
136
136
  </div>}
137
137
  <DoNotDisturbOnIcon color={"disabled"} size={"small"} className={"absolute -right-2 -top-2"}/>
138
138
  </div>
@@ -147,7 +147,7 @@ export function NonEditablePropertyPreview({
147
147
  >
148
148
 
149
149
  <div className="w-full flex flex-col">
150
- <Typography variant="body1"
150
+ <Typography variant="label"
151
151
  component="span"
152
152
  className="flex-grow pr-2">
153
153
  {property?.name
@@ -26,7 +26,7 @@ export function UnsavedChangesDialog({
26
26
  >
27
27
 
28
28
  <DialogTitle>{title ?? "Unsaved changes"}</DialogTitle>
29
- <DialogContent>
29
+ <DialogContent className={"mt-4"}>
30
30
  {body && <Typography>
31
31
  {body}
32
32
  </Typography>}
@@ -4,6 +4,7 @@ import {
4
4
  EntityCollectionTable,
5
5
  Properties,
6
6
  useAuthController,
7
+ useNavigationController,
7
8
  useSelectionController
8
9
  } from "@firecms/core";
9
10
  import { useEffect, useState } from "react";
@@ -20,11 +21,18 @@ export function CollectionEditorImportDataPreview({
20
21
  }) {
21
22
 
22
23
  const authController = useAuthController();
24
+ const navigation = useNavigationController();
23
25
  const [loading, setLoading] = useState<boolean>(false);
24
26
 
25
27
  async function loadEntities() {
26
- // const propertiesMapping = getPropertiesMapping(importConfig.originProperties, properties, importConfig.headersMapping);
27
- const mappedData = importConfig.importData.map(d => convertDataToEntity(authController, d, importConfig.idColumn, importConfig.headersMapping, properties, "TEMP_PATH", importConfig.defaultValues));
28
+ const mappedData = importConfig.importData.map(d => convertDataToEntity(authController,
29
+ navigation,
30
+ d,
31
+ importConfig.idColumn,
32
+ importConfig.headersMapping,
33
+ properties,
34
+ "TEMP_PATH",
35
+ importConfig.defaultValues));
28
36
  importConfig.setEntities(mappedData);
29
37
  }
30
38
 
@@ -57,7 +57,7 @@ export function MarkdownPropertyField({
57
57
  <div className="flex flex-row text-surface-500">
58
58
  <CloudUploadIcon/>
59
59
  <Typography variant={"subtitle2"}
60
- className="ml-2">
60
+ className="ml-4">
61
61
  File upload config
62
62
  </Typography>
63
63
  </div>
@@ -6,6 +6,8 @@ import {
6
6
  ExpandablePanel,
7
7
  MultiSelect,
8
8
  MultiSelectItem,
9
+ Select,
10
+ SelectItem,
9
11
  Typography
10
12
  } from "@firecms/ui";
11
13
 
@@ -47,20 +49,31 @@ export function StoragePropertyField({
47
49
  const storagePath = `${baseStoragePath}.storagePath`;
48
50
  const storeUrl = `${baseStoragePath}.storeUrl`;
49
51
 
52
+ // Image resize config paths
53
+ const imageResize = `${baseStoragePath}.imageResize`;
54
+ const imageResizeMaxWidth = `${imageResize}.maxWidth`;
55
+ const imageResizeMaxHeight = `${imageResize}.maxHeight`;
56
+ const imageResizeMode = `${imageResize}.mode`;
57
+ const imageResizeFormat = `${imageResize}.format`;
58
+ const imageResizeQuality = `${imageResize}.quality`;
59
+
50
60
  const fileNameValue = getIn(values, fileName) ?? "{rand}_{file}";
51
61
  const storagePathValue = getIn(values, storagePath) ?? "/";
52
62
  const maxSizeValue = getIn(values, maxSize);
53
63
 
64
+ // Image resize values
65
+ const imageResizeMaxWidthValue = getIn(values, imageResizeMaxWidth);
66
+ const imageResizeMaxHeightValue = getIn(values, imageResizeMaxHeight);
67
+ const imageResizeModeValue = getIn(values, imageResizeMode) ?? "cover";
68
+ const imageResizeFormatValue = getIn(values, imageResizeFormat) ?? "original";
69
+ const imageResizeQualityValue = getIn(values, imageResizeQuality);
70
+
54
71
  const storedValue = getIn(values, acceptedFiles);
55
72
  const fileTypesValue: string[] | undefined = Array.isArray(storedValue) ? storedValue : undefined;
56
73
  const allFileTypesSelected = !fileTypesValue || fileTypesValue.length === 0;
57
74
 
58
75
  const handleTypesChange = (value: string[]) => {
59
76
  if (!value) setFieldValue(acceptedFiles, undefined);
60
- // else if (value.includes("all")) setFieldValue(acceptedFiles, undefined);
61
- // else if (value.length >= Object.keys(fileTypes).length) setFieldValue(acceptedFiles, undefined);
62
- // else if (allFileTypesSelected)
63
- // setFieldValue(acceptedFiles, Object.keys(fileTypes).filter((v) => !value.includes(v)));
64
77
  else setFieldValue(acceptedFiles, value);
65
78
  };
66
79
 
@@ -77,7 +90,7 @@ export function StoragePropertyField({
77
90
  <div className="flex flex-row text-surface-500">
78
91
  <CloudUploadIcon/>
79
92
  <Typography variant={"subtitle2"}
80
- className="ml-2">
93
+ className="ml-4">
81
94
  File upload config
82
95
  </Typography>
83
96
  </div>
@@ -193,6 +206,123 @@ export function StoragePropertyField({
193
206
  />
194
207
  </div>
195
208
 
209
+ <div className={"col-span-12 mt-4"}>
210
+ <Typography variant={"subtitle2"}
211
+ color={"secondary"}
212
+ className={"mb-2 block"}>
213
+ Image Resize Configuration
214
+ </Typography>
215
+ <Typography variant={"caption"} className={"mb-2 block text-xs"}>
216
+ Automatically resize and optimize images before upload (JPEG, PNG, WebP only)
217
+ </Typography>
218
+ </div>
219
+
220
+ <div className={"col-span-6"}>
221
+ <DebouncedTextField
222
+ name={imageResizeMaxWidth}
223
+ type={"number"}
224
+ label={"Max width (px)"}
225
+ size={"small"}
226
+ disabled={disabled}
227
+ value={imageResizeMaxWidthValue !== undefined && imageResizeMaxWidthValue !== null ? imageResizeMaxWidthValue.toString() : ""}
228
+ onChange={(e) => {
229
+ const value = e.target.value;
230
+ if (value === "") setFieldValue(imageResizeMaxWidth, undefined);
231
+ else setFieldValue(imageResizeMaxWidth, parseInt(value));
232
+ }}
233
+ />
234
+ </div>
235
+
236
+ <div className={"col-span-6"}>
237
+ <DebouncedTextField
238
+ name={imageResizeMaxHeight}
239
+ type={"number"}
240
+ label={"Max height (px)"}
241
+ size={"small"}
242
+ disabled={disabled}
243
+ value={imageResizeMaxHeightValue !== undefined && imageResizeMaxHeightValue !== null ? imageResizeMaxHeightValue.toString() : ""}
244
+ onChange={(e) => {
245
+ const value = e.target.value;
246
+ if (value === "") setFieldValue(imageResizeMaxHeight, undefined);
247
+ else setFieldValue(imageResizeMaxHeight, parseInt(value));
248
+ }}
249
+ />
250
+ </div>
251
+
252
+ <div className={"col-span-6"}>
253
+ <Select
254
+ disabled={disabled}
255
+ name={imageResizeMode}
256
+ fullWidth
257
+ size={"medium"}
258
+ value={imageResizeModeValue || "cover"}
259
+ onValueChange={(value) => setFieldValue(imageResizeMode, value || "cover")}
260
+ label={"Resize mode"}
261
+ renderValue={(selected) => {
262
+ if (!selected) return "Cover";
263
+ return selected === "contain" ? "Contain (fit within bounds)" : "Cover (fill bounds, may crop)";
264
+ }}>
265
+ <SelectItem value="contain">
266
+ Contain (fit within bounds)
267
+ </SelectItem>
268
+ <SelectItem value="cover">
269
+ Cover (fill bounds, may crop)
270
+ </SelectItem>
271
+ </Select>
272
+ </div>
273
+
274
+ <div className={"col-span-6"}>
275
+ <Select
276
+ disabled={disabled}
277
+ size={"medium"}
278
+ fullWidth
279
+ name={imageResizeFormat}
280
+ value={imageResizeFormatValue || "original"}
281
+ onValueChange={(value) => setFieldValue(imageResizeFormat, value || "original")}
282
+ label={"Output format"}
283
+ renderValue={(selected) => {
284
+ if (!selected) return "Original";
285
+ return selected.charAt(0).toUpperCase() + selected.slice(1);
286
+ }}>
287
+ <SelectItem value="original">
288
+ Original (keep same format)
289
+ </SelectItem>
290
+ <SelectItem value="jpeg">
291
+ JPEG
292
+ </SelectItem>
293
+ <SelectItem value="png">
294
+ PNG
295
+ </SelectItem>
296
+ <SelectItem value="webp">
297
+ WebP (best compression)
298
+ </SelectItem>
299
+ </Select>
300
+ </div>
301
+
302
+ <div className={"col-span-12"}>
303
+ <DebouncedTextField
304
+ name={imageResizeQuality}
305
+ type={"number"}
306
+ label={"Quality (0-100)"}
307
+ size={"small"}
308
+ disabled={disabled}
309
+ value={imageResizeQualityValue !== undefined && imageResizeQualityValue !== null ? imageResizeQualityValue.toString() : ""}
310
+ onChange={(e) => {
311
+ const value = e.target.value;
312
+ if (value === "") setFieldValue(imageResizeQuality, undefined);
313
+ else {
314
+ const numValue = parseInt(value);
315
+ if (numValue >= 0 && numValue <= 100) {
316
+ setFieldValue(imageResizeQuality, numValue);
317
+ }
318
+ }
319
+ }}
320
+ />
321
+ <Typography variant={"caption"} className={"ml-3.5 mt-1 mb-2"}>
322
+ Higher quality = larger file size. Recommended: 80-90 for photos, 90-100 for graphics
323
+ </Typography>
324
+ </div>
325
+
196
326
  </div>
197
327
  </ExpandablePanel>
198
328
 
@@ -10,7 +10,7 @@ export function StringPropertyField({
10
10
  disabled,
11
11
  showErrors
12
12
  }: {
13
- widgetId: "text_field" | "multiline" | "email";
13
+ widgetId: "text_field" | "multiline" | "email" | "user_select";
14
14
  disabled: boolean;
15
15
  showErrors: boolean;
16
16
  }) {
@@ -33,6 +33,10 @@ export function StringPropertyField({
33
33
  trim={true}
34
34
  uppercase={true}
35
35
  showErrors={showErrors}/>}
36
+ {widgetId === "user_select" &&
37
+ <StringPropertyValidation disabled={disabled}
38
+ showErrors={showErrors}/>}
39
+
36
40
  {widgetId === "multiline" &&
37
41
  <StringPropertyValidation disabled={disabled}
38
42
  length={true}
@@ -15,7 +15,7 @@ export function ValidationPanel({
15
15
  <div className="flex flex-row text-surface-500">
16
16
  <RuleIcon/>
17
17
  <Typography variant={"subtitle2"}
18
- className="ml-2">
18
+ className="ml-4">
19
19
  Validation
20
20
  </Typography>
21
21
  </div>
@@ -6,6 +6,7 @@ export const supportedFieldsIds: PropertyConfigId[] = [
6
6
  "markdown",
7
7
  "url",
8
8
  "email",
9
+ "user_select",
9
10
  "select",
10
11
  "multi_select",
11
12
  "number_input",
@@ -27,7 +27,24 @@ export function updatePropertyFromWidget(propertyData: any,
27
27
  markdown: undefined,
28
28
  email: undefined,
29
29
  url: undefined,
30
- enumValues: undefined
30
+ enumValues: undefined,
31
+ userSelect: undefined
32
+ } satisfies StringProperty
33
+ );
34
+ } else if (selectedWidgetId === "user_select") {
35
+ updatedProperty = mergeDeep(
36
+ propertyData,
37
+ {
38
+ dataType: "string",
39
+ propertyConfig: "user_select",
40
+ editable: propertyData.editable !== undefined ? propertyData.editable : true,
41
+ storage: undefined,
42
+ multiline: undefined,
43
+ markdown: undefined,
44
+ email: undefined,
45
+ url: undefined,
46
+ enumValues: undefined,
47
+ userSelect: true
31
48
  } satisfies StringProperty
32
49
  );
33
50
  } else if (selectedWidgetId === "multiline") {
@@ -42,7 +59,8 @@ export function updatePropertyFromWidget(propertyData: any,
42
59
  markdown: undefined,
43
60
  email: undefined,
44
61
  url: undefined,
45
- enumValues: undefined
62
+ enumValues: undefined,
63
+ userSelect: undefined
46
64
  } satisfies StringProperty
47
65
  );
48
66
  } else if (selectedWidgetId === "markdown") {
@@ -56,7 +74,8 @@ export function updatePropertyFromWidget(propertyData: any,
56
74
  multiline: undefined,
57
75
  markdown: true,
58
76
  email: undefined,
59
- url: undefined
77
+ url: undefined,
78
+ userSelect: undefined
60
79
  } satisfies StringProperty
61
80
  );
62
81
  } else if (selectedWidgetId === "url") {
@@ -71,7 +90,8 @@ export function updatePropertyFromWidget(propertyData: any,
71
90
  markdown: undefined,
72
91
  email: undefined,
73
92
  url: true,
74
- enumValues: undefined
93
+ enumValues: undefined,
94
+ userSelect: undefined
75
95
  } satisfies StringProperty
76
96
  );
77
97
  } else if (selectedWidgetId === "email") {
@@ -86,7 +106,8 @@ export function updatePropertyFromWidget(propertyData: any,
86
106
  markdown: undefined,
87
107
  email: true,
88
108
  url: undefined,
89
- enumValues: undefined
109
+ enumValues: undefined,
110
+ userSelect: undefined
90
111
  } satisfies StringProperty
91
112
  );
92
113
  } else if (selectedWidgetId === "select") {
@@ -101,7 +122,8 @@ export function updatePropertyFromWidget(propertyData: any,
101
122
  markdown: undefined,
102
123
  email: undefined,
103
124
  url: undefined,
104
- enumValues: propertyData.enumValues ?? []
125
+ enumValues: propertyData.enumValues ?? [],
126
+ userSelect: undefined
105
127
  } satisfies StringProperty
106
128
  );
107
129
  } else if (selectedWidgetId === "multi_select") {
@@ -1,5 +1,4 @@
1
1
  import {
2
- EntityCallbacks,
3
2
  EntityCollection,
4
3
  joinCollectionLists,
5
4
  makePropertiesEditable,
@@ -1,17 +1,14 @@
1
1
  import { isPropertyBuilder, Properties, PropertiesOrBuilders, Property, PropertyOrBuilder } from "@firecms/core";
2
2
 
3
- export function editableProperty(property: PropertyOrBuilder | PropertyOrBuilder): boolean {
4
- if (isPropertyBuilder(property))
3
+ export function editableProperty(property: PropertyOrBuilder): boolean {
4
+ if (isPropertyBuilder(property)) {
5
5
  return false;
6
- if (isPropertyBuilder(property as PropertyOrBuilder))
7
- return false;
8
- else {
9
- const eProperty = property as Property;
10
- if (eProperty.dataType === "array" && typeof eProperty.of === "function")
6
+ } else {
7
+ if (property.dataType === "array" && typeof property.of === "function")
11
8
  return false;
12
- else if (eProperty.dataType === "array" && Array.isArray(eProperty.of))
9
+ else if (property.dataType === "array" && Array.isArray(property.of))
13
10
  return false;
14
- return Boolean(eProperty.editable);
11
+ return property.editable === undefined ? true : Boolean(property.editable);
15
12
  }
16
13
  }
17
14