@firecms/collection_editor 3.0.0-beta.10 → 3.0.0-beta.11

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 (35) hide show
  1. package/dist/index.es.js +8975 -5244
  2. package/dist/index.es.js.map +1 -1
  3. package/dist/index.umd.js +8967 -5237
  4. package/dist/index.umd.js.map +1 -1
  5. package/dist/types/config_permissions.d.ts +2 -2
  6. package/dist/types/persisted_collection.d.ts +1 -1
  7. package/dist/useCollectionEditorPlugin.d.ts +4 -4
  8. package/package.json +18 -16
  9. package/src/types/config_permissions.ts +1 -1
  10. package/src/types/persisted_collection.ts +2 -3
  11. package/src/ui/CollectionViewHeaderAction.tsx +1 -1
  12. package/src/ui/NewCollectionButton.tsx +1 -1
  13. package/src/ui/PropertyAddColumnComponent.tsx +2 -2
  14. package/src/ui/collection_editor/CollectionDetailsForm.tsx +8 -4
  15. package/src/ui/collection_editor/CollectionEditorDialog.tsx +9 -5
  16. package/src/ui/collection_editor/CollectionEditorWelcomeView.tsx +2 -2
  17. package/src/ui/collection_editor/CollectionPropertiesEditorForm.tsx +5 -9
  18. package/src/ui/collection_editor/EntityCustomViewsSelectDialog.tsx +6 -5
  19. package/src/ui/collection_editor/EnumForm.tsx +10 -6
  20. package/src/ui/collection_editor/GetCodeDialog.tsx +41 -23
  21. package/src/ui/collection_editor/PropertyEditView.tsx +7 -4
  22. package/src/ui/collection_editor/PropertyFieldPreview.tsx +4 -4
  23. package/src/ui/collection_editor/PropertyTree.tsx +2 -2
  24. package/src/ui/collection_editor/UnsavedChangesDialog.tsx +3 -5
  25. package/src/ui/collection_editor/import/CollectionEditorImportMapping.tsx +2 -0
  26. package/src/ui/collection_editor/properties/BlockPropertyField.tsx +18 -12
  27. package/src/ui/collection_editor/properties/DateTimePropertyField.tsx +4 -0
  28. package/src/ui/collection_editor/properties/EnumPropertyField.tsx +2 -0
  29. package/src/ui/collection_editor/properties/MapPropertyField.tsx +2 -1
  30. package/src/ui/collection_editor/properties/MarkdownPropertyField.tsx +3 -3
  31. package/src/ui/collection_editor/properties/ReferencePropertyField.tsx +2 -0
  32. package/src/ui/collection_editor/properties/StoragePropertyField.tsx +3 -3
  33. package/src/ui/collection_editor/properties/UrlPropertyField.tsx +1 -0
  34. package/src/ui/collection_editor/properties/validation/ValidationPanel.tsx +1 -1
  35. package/src/useCollectionEditorPlugin.tsx +6 -6
@@ -1,6 +1,6 @@
1
1
  import { EntityCollection } from "@firecms/core";
2
- export type CollectionEditorPermissionsBuilder<UserType = any, EC extends EntityCollection = EntityCollection> = (params: {
3
- user: UserType | null;
2
+ export type CollectionEditorPermissionsBuilder<USER = any, EC extends EntityCollection = EntityCollection> = (params: {
3
+ user: USER | null;
4
4
  collection?: EC;
5
5
  }) => CollectionEditorPermissions;
6
6
  export type CollectionEditorPermissions = {
@@ -1,5 +1,5 @@
1
1
  import { EntityCollection, User } from "@firecms/core";
2
- export type PersistedCollection<M extends Record<string, any> = any, UserType extends User = User> = Omit<EntityCollection<M, UserType>, "subcollections"> & {
2
+ export type PersistedCollection<M extends Record<string, any> = any, USER extends User = User> = Omit<EntityCollection<M, USER>, "subcollections"> & {
3
3
  ownerId?: string;
4
4
  subcollections?: PersistedCollection<any, any>[];
5
5
  editable?: boolean;
@@ -4,7 +4,7 @@ import { CollectionEditorPermissionsBuilder } from "./types/config_permissions";
4
4
  import { PersistedCollection } from "./types/persisted_collection";
5
5
  import { CollectionInference } from "./types/collection_inference";
6
6
  import { CollectionsConfigController } from "./types/config_controller";
7
- export interface CollectionConfigControllerProps<EC extends PersistedCollection = PersistedCollection, UserType extends User = User> {
7
+ export interface CollectionConfigControllerProps<EC extends PersistedCollection = PersistedCollection, USER extends User = User> {
8
8
  /**
9
9
  * Firebase app where the configuration is saved.
10
10
  */
@@ -12,7 +12,7 @@ export interface CollectionConfigControllerProps<EC extends PersistedCollection
12
12
  /**
13
13
  * Define what actions can be performed on the configuration.
14
14
  */
15
- configPermissions?: CollectionEditorPermissionsBuilder<UserType, EC>;
15
+ configPermissions?: CollectionEditorPermissionsBuilder<USER, EC>;
16
16
  /**
17
17
  * The words you define here will not be allowed to be used as group
18
18
  * names when creating collections.
@@ -28,7 +28,7 @@ export interface CollectionConfigControllerProps<EC extends PersistedCollection
28
28
  getPathSuggestions?: (path?: string) => Promise<string[]>;
29
29
  collectionInference?: CollectionInference;
30
30
  getData?: (path: string, parentPaths: string[]) => Promise<object[]>;
31
- getUser?: (uid: string) => UserType | null;
31
+ getUser?: (uid: string) => USER | null;
32
32
  onAnalyticsEvent?: (event: string, params?: object) => void;
33
33
  components?: {
34
34
  /**
@@ -51,5 +51,5 @@ export interface CollectionConfigControllerProps<EC extends PersistedCollection
51
51
  * @param getUser
52
52
  * @param collectionInference
53
53
  */
54
- export declare function useCollectionEditorPlugin<EC extends PersistedCollection = PersistedCollection, UserType extends User = User>({ collectionConfigController, configPermissions, reservedGroups, extraView, getPathSuggestions, getUser, collectionInference, getData, onAnalyticsEvent, components }: CollectionConfigControllerProps<EC, UserType>): FireCMSPlugin<any, any, PersistedCollection>;
54
+ export declare function useCollectionEditorPlugin<EC extends PersistedCollection = PersistedCollection, USER extends User = User>({ collectionConfigController, configPermissions, reservedGroups, extraView, getPathSuggestions, getUser, collectionInference, getData, onAnalyticsEvent, components }: CollectionConfigControllerProps<EC, USER>): FireCMSPlugin<any, any, PersistedCollection>;
55
55
  export declare function IntroWidget({}: {}): import("react/jsx-runtime").JSX.Element | null;
package/package.json CHANGED
@@ -1,26 +1,26 @@
1
1
  {
2
2
  "name": "@firecms/collection_editor",
3
3
  "type": "module",
4
- "version": "3.0.0-beta.10",
4
+ "version": "3.0.0-beta.11",
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-beta.10",
11
- "@firecms/data_import": "^3.0.0-beta.10",
12
- "@firecms/data_import_export": "^3.0.0-beta.10",
13
- "@firecms/formex": "^3.0.0-beta.10",
14
- "@firecms/schema_inference": "^3.0.0-beta.10",
15
- "@firecms/ui": "^3.0.0-beta.10",
10
+ "@firecms/data_export": "^3.0.0-beta.11",
11
+ "@firecms/data_import": "^3.0.0-beta.11",
12
+ "@firecms/data_import_export": "^3.0.0-beta.11",
13
+ "@firecms/formex": "^3.0.0-beta.11",
14
+ "@firecms/schema_inference": "^3.0.0-beta.11",
15
+ "@firecms/ui": "^3.0.0-beta.11",
16
16
  "json5": "^2.2.3",
17
17
  "prism-react-renderer": "^2.4.0"
18
18
  },
19
19
  "peerDependencies": {
20
20
  "react": "^18.3.1",
21
21
  "react-dom": "^18.3.1",
22
- "react-router": "^6.25.1",
23
- "react-router-dom": "^6.25.1"
22
+ "react-router": "^6.28.0",
23
+ "react-router-dom": "^6.28.0"
24
24
  },
25
25
  "exports": {
26
26
  ".": {
@@ -51,14 +51,16 @@
51
51
  "devDependencies": {
52
52
  "@jest/globals": "^29.7.0",
53
53
  "@types/react": "^18.3.11",
54
- "@types/react-dom": "^18.3.0",
55
- "@vitejs/plugin-react": "^4.3.2",
54
+ "@types/react-dom": "^18.3.1",
55
+ "@vitejs/plugin-react": "^4.3.4",
56
+ "babel-plugin-react-compiler": "beta",
57
+ "eslint-plugin-react-compiler": "beta",
56
58
  "jest": "^29.7.0",
57
- "react-router": "^6.26.2",
58
- "react-router-dom": "^6.26.2",
59
+ "react-router": "^6.28.0",
60
+ "react-router-dom": "^6.28.0",
59
61
  "ts-jest": "^29.2.5",
60
- "typescript": "^5.6.3",
61
- "vite": "^5.4.8"
62
+ "typescript": "^5.7.2",
63
+ "vite": "^5.4.11"
62
64
  },
63
65
  "files": [
64
66
  "dist",
@@ -67,5 +69,5 @@
67
69
  "publishConfig": {
68
70
  "access": "public"
69
71
  },
70
- "gitHead": "f844c3f86094efec6c33313c3f106f30cdcd309f"
72
+ "gitHead": "cb6d419faf2664cfd6cb2603a834e4bf499a92bb"
71
73
  }
@@ -1,6 +1,6 @@
1
1
  import { EntityCollection } from "@firecms/core";
2
2
 
3
- export type CollectionEditorPermissionsBuilder<UserType = any, EC extends EntityCollection = EntityCollection> = (params: { user: UserType | null, collection?: EC }) => CollectionEditorPermissions;
3
+ export type CollectionEditorPermissionsBuilder<USER = any, EC extends EntityCollection = EntityCollection> = (params: { user: USER | null, collection?: EC }) => CollectionEditorPermissions;
4
4
 
5
5
  export type CollectionEditorPermissions = {
6
6
  /**
@@ -1,8 +1,7 @@
1
1
  import { EntityCollection, User } from "@firecms/core";
2
2
 
3
- export type PersistedCollection<M extends Record<string, any> = any, UserType extends User = User>
4
- = Omit<EntityCollection<M, UserType>, "subcollections"> & {
5
- // properties: Properties<M>;
3
+ export type PersistedCollection<M extends Record<string, any> = any, USER extends User = User>
4
+ = Omit<EntityCollection<M, USER>, "subcollections"> & {
6
5
  ownerId?: string;
7
6
  subcollections?: PersistedCollection<any, any>[];
8
7
  editable?: boolean;
@@ -29,7 +29,7 @@ export function CollectionViewHeaderAction({
29
29
  asChild={true}
30
30
  title={"Edit"}>
31
31
  <IconButton
32
- className={onHover ? "bg-white dark:bg-gray-950" : "hidden"}
32
+ className={onHover ? "bg-white dark:bg-surface-950" : "hidden"}
33
33
  onClick={() => {
34
34
  collectionEditorController.editProperty({
35
35
  propertyKey,
@@ -3,7 +3,7 @@ import { useCollectionEditorController } from "../useCollectionEditorController"
3
3
 
4
4
  export function NewCollectionButton() {
5
5
  const collectionEditorController = useCollectionEditorController();
6
- return <div className={"bg-gray-50 dark:bg-gray-900 min-w-fit rounded"}>
6
+ return <div className={"bg-surface-50 dark:bg-surface-900 min-w-fit rounded"}>
7
7
  <Button className={"min-w-fit"}
8
8
  variant={"outlined"}
9
9
  onClick={() => collectionEditorController.createCollection({
@@ -29,8 +29,8 @@ export function PropertyAddColumnComponent({
29
29
  asChild={true}
30
30
  title={canEditCollection ? "Add new property" : "You don't have permission to add new properties"}>
31
31
  <div
32
- className={"p-0.5 w-20 h-full flex items-center justify-center cursor-pointer bg-gray-100 bg-opacity-40 hover:bg-gray-100 dark:bg-gray-950 dark:bg-opacity-40 dark:hover:bg-gray-950"}
33
- // className={onHover ? "bg-white dark:bg-gray-950" : undefined}
32
+ className={"p-0.5 w-20 h-full flex items-center justify-center cursor-pointer bg-surface-100 bg-opacity-40 hover:bg-surface-100 dark:bg-surface-950 dark:bg-opacity-40 dark:hover:bg-surface-950"}
33
+ // className={onHover ? "bg-white dark:bg-surface-950" : undefined}
34
34
  onClick={() => {
35
35
  collectionEditorController.editProperty({
36
36
  editedCollectionId: collection.id,
@@ -5,7 +5,7 @@ import {
5
5
  AutocompleteItem,
6
6
  BooleanSwitchWithLabel,
7
7
  Chip,
8
- ClearIcon,
8
+ CloseIcon,
9
9
  cls,
10
10
  Container,
11
11
  DebouncedTextField,
@@ -214,7 +214,7 @@ export function CollectionDetailsForm({
214
214
  expanded={advancedPanelExpanded}
215
215
  onExpandedChange={setAdvancedPanelExpanded}
216
216
  title={
217
- <div className="flex flex-row text-gray-500">
217
+ <div className="flex flex-row text-surface-500">
218
218
  <SettingsIcon/>
219
219
  <Typography variant={"subtitle2"}
220
220
  className="ml-2">
@@ -271,7 +271,7 @@ export function CollectionDetailsForm({
271
271
  setFieldValue("sideDialogWidth", null);
272
272
  }}
273
273
  disabled={!values.sideDialogWidth}>
274
- <ClearIcon size={"small"}/>
274
+ <CloseIcon size={"small"}/>
275
275
  </IconButton>}
276
276
  value={values.sideDialogWidth ?? ""}
277
277
  label={"Side dialog width"}/>
@@ -298,6 +298,8 @@ export function CollectionDetailsForm({
298
298
  <div className={"col-span-12"}>
299
299
  <Select
300
300
  name="defaultSize"
301
+ size={"large"}
302
+ fullWidth={true}
301
303
  label="Default row size"
302
304
  position={"item-aligned"}
303
305
  onChange={handleChange}
@@ -318,6 +320,8 @@ export function CollectionDetailsForm({
318
320
  name="customId"
319
321
  label="Document IDs generation"
320
322
  position={"item-aligned"}
323
+ size={"large"}
324
+ fullWidth={true}
321
325
  disabled={customIdValue === "code_defined"}
322
326
  onValueChange={(v) => {
323
327
  if (v === "code_defined")
@@ -416,7 +420,7 @@ function DefaultDatabaseField({
416
420
  return <Tooltip title={"Database ID"}
417
421
  side={"top"}
418
422
  align={"start"}>
419
- <TextField size={"smallest"}
423
+ <TextField size={"small"}
420
424
  invisible={true}
421
425
  inputClassName={"text-end"}
422
426
  value={databaseId ?? ""}
@@ -26,13 +26,14 @@ import {
26
26
  import {
27
27
  ArrowBackIcon,
28
28
  Button,
29
+ CheckIcon,
29
30
  cls,
30
31
  coolIconKeys,
31
32
  defaultBorderMixin,
32
33
  Dialog,
33
34
  DialogActions,
34
35
  DialogContent,
35
- DoneIcon,
36
+ DialogTitle,
36
37
  IconButton,
37
38
  LoadingButton,
38
39
  Tab,
@@ -114,6 +115,7 @@ export function CollectionEditorDialog(props: CollectionEditorDialogProps) {
114
115
  maxWidth={"7xl"}
115
116
  onOpenChange={(open) => !open ? handleCancel() : undefined}
116
117
  >
118
+ <DialogTitle hidden>Collection editor</DialogTitle>
117
119
  {open && <CollectionEditor {...props}
118
120
  handleCancel={handleCancel}
119
121
  setFormDirty={setFormDirty}/>}
@@ -276,6 +278,7 @@ function CollectionEditorInternal<M extends Record<string, any>>({
276
278
 
277
279
  const saveCollection = (updatedCollection: PersistedCollection<M>): Promise<boolean> => {
278
280
  const id = updatedCollection.id || updatedCollection.path;
281
+
279
282
  return configController.saveCollection({
280
283
  id,
281
284
  collectionData: updatedCollection,
@@ -377,7 +380,7 @@ function CollectionEditorInternal<M extends Record<string, any>>({
377
380
 
378
381
  if (!isNewCollection) {
379
382
  saveCollection(newCollectionState).then(() => {
380
- formexController.resetForm({ values: initialValues });
383
+ formexController.resetForm();
381
384
  handleClose(newCollectionState);
382
385
  });
383
386
  return;
@@ -466,7 +469,8 @@ function CollectionEditorInternal<M extends Record<string, any>>({
466
469
  const formController = useCreateFormex<PersistedCollection<M>>({
467
470
  initialValues,
468
471
  onSubmit,
469
- validation
472
+ validation,
473
+ debugId: "COLLECTION_EDITOR"
470
474
  });
471
475
 
472
476
  const {
@@ -536,7 +540,7 @@ function CollectionEditorInternal<M extends Record<string, any>>({
536
540
 
537
541
  <>
538
542
  {!isNewCollection && <Tabs value={currentView}
539
- className={cls(defaultBorderMixin, "justify-end bg-gray-50 dark:bg-gray-950 border-b")}
543
+ innerClassName={cls(defaultBorderMixin, "justify-end bg-surface-50 dark:bg-surface-950 border-b")}
540
544
  onValueChange={(v) => setCurrentView(v as EditorView)}>
541
545
  <Tab value={"details"}>
542
546
  Details
@@ -722,7 +726,7 @@ function CollectionEditorInternal<M extends Record<string, any>>({
722
726
  loading={isSubmitting}
723
727
  disabled={isSubmitting || (currentView === "details" && !validValues)}
724
728
  startIcon={currentView === "properties"
725
- ? <DoneIcon/>
729
+ ? <CheckIcon/>
726
730
  : undefined}
727
731
  >
728
732
  {currentView === "details" && "Next"}
@@ -191,9 +191,9 @@ export function TemplateButton({
191
191
  onClick={onClick}
192
192
  className={cls(
193
193
  "my-2 rounded-md border mx-0 p-6 px-4 focus:outline-none transition ease-in-out duration-150 flex flex-row gap-4 items-center",
194
- "text-gray-700 dark:text-slate-300",
194
+ "text-surface-700 dark:text-surface-accent-300",
195
195
  "hover:border-primary-dark hover:text-primary-dark dark:hover:text-primary focus:ring-primary hover:ring-1 hover:ring-primary",
196
- "border-gray-400 dark:border-gray-600 "
196
+ "border-surface-400 dark:border-surface-600 "
197
197
  )}
198
198
  >
199
199
  {icon}
@@ -16,7 +16,7 @@ import {
16
16
  } from "@firecms/core";
17
17
  import {
18
18
  AddIcon,
19
- AutoAwesomeIcon,
19
+ AutorenewIcon,
20
20
  Button,
21
21
  CircularProgress,
22
22
  cls,
@@ -228,17 +228,13 @@ export function CollectionPropertiesEditorForm({
228
228
  namespace
229
229
  }: OnPropertyChangedParams) => {
230
230
 
231
+ console.log("!!!!!! onPropertyChanged", property)
232
+
231
233
  const fullId = id ? getFullId(id, namespace) : undefined;
232
234
  const propertyPath = fullId ? idToPropertiesPath(fullId) : undefined;
233
235
 
234
236
  // If the id has changed we need to a little cleanup
235
237
  if (previousId && previousId !== id) {
236
- console.debug("onPropertyChanged, id change", {
237
- id,
238
- property,
239
- previousId,
240
- namespace
241
- })
242
238
 
243
239
  const previousFullId = getFullId(previousId, namespace);
244
240
  const previousPropertyPath = idToPropertiesPath(previousFullId);
@@ -316,7 +312,7 @@ export function CollectionPropertiesEditorForm({
316
312
  };
317
313
 
318
314
  const body = (
319
- <div className={"grid grid-cols-12 gap-2 h-full bg-gray-50 dark:bg-gray-900"}>
315
+ <div className={"grid grid-cols-12 gap-2 h-full bg-surface-50 dark:bg-surface-900"}>
320
316
  <div className={cls(
321
317
  "p-4 md:p-8 pb-20 md:pb-20",
322
318
  "col-span-12 lg:col-span-5 h-full overflow-auto",
@@ -366,7 +362,7 @@ export function CollectionPropertiesEditorForm({
366
362
  variant={"filled"}
367
363
  disabled={inferringProperties}
368
364
  onClick={inferPropertiesFromData}>
369
- {inferringProperties ? <CircularProgress size={"small"}/> : <AutoAwesomeIcon/>}
365
+ {inferringProperties ? <CircularProgress size={"small"}/> : <AutorenewIcon/>}
370
366
  </IconButton>
371
367
  </Tooltip>}
372
368
  <Tooltip title={"Add new property"}
@@ -1,8 +1,11 @@
1
1
  import { useCustomizationController } from "@firecms/core";
2
- import { Button, Dialog, DialogActions, DialogContent, Typography } from "@firecms/ui";
2
+ import { Button, Dialog, DialogActions, DialogContent, DialogTitle, Typography } from "@firecms/ui";
3
3
  import React from "react";
4
4
 
5
- export function EntityCustomViewsSelectDialog({ open, onClose }: { open: boolean, onClose: (selectedViewKey?: string) => void }) {
5
+ export function EntityCustomViewsSelectDialog({
6
+ open,
7
+ onClose
8
+ }: { open: boolean, onClose: (selectedViewKey?: string) => void }) {
6
9
  const {
7
10
  entityViews,
8
11
  } = useCustomizationController();
@@ -10,10 +13,8 @@ export function EntityCustomViewsSelectDialog({ open, onClose }: { open: boolean
10
13
  return <Dialog
11
14
  maxWidth={"md"}
12
15
  open={open}>
16
+ <DialogTitle>Select custom view</DialogTitle>
13
17
  <DialogContent className={"flex flex-col gap-4"}>
14
- <Typography variant={"h6"}>
15
- Select view
16
- </Typography>
17
18
  {entityViews?.map((view) => {
18
19
  return <Button
19
20
  key={view.key}
@@ -1,9 +1,9 @@
1
1
  import React, { useEffect } from "react";
2
2
  import equal from "react-fast-compare"
3
3
 
4
- import { ArrayContainer, EnumValueConfig, EnumValues, FieldCaption, } from "@firecms/core";
4
+ import { ArrayContainer, ArrayEntryParams, EnumValueConfig, EnumValues, FieldCaption, } from "@firecms/core";
5
5
  import {
6
- AutoAwesomeIcon,
6
+ AutorenewIcon,
7
7
  Badge,
8
8
  Button,
9
9
  CircularProgress,
@@ -11,6 +11,7 @@ import {
11
11
  Dialog,
12
12
  DialogActions,
13
13
  DialogContent,
14
+ DialogTitle,
14
15
  IconButton,
15
16
  ListIcon,
16
17
  Paper,
@@ -121,7 +122,10 @@ function EnumFormFields({
121
122
  const inferredValuesRef = React.useRef(new Set());
122
123
  const inferredValues = inferredValuesRef.current;
123
124
 
124
- const buildEntry = (index: number, internalId: number) => {
125
+ const buildEntry = ({
126
+ index,
127
+ internalId
128
+ }:ArrayEntryParams) => {
125
129
  const justAdded = lastInternalIdAdded === internalId;
126
130
  const entryError = errors?.enumValues && errors?.enumValues[index];
127
131
  return <EnumEntry index={index}
@@ -179,7 +183,7 @@ function EnumFormFields({
179
183
  variant={"text"}
180
184
  size={"small"}
181
185
  onClick={inferValues}>
182
- {inferring ? <CircularProgress size={"small"}/> : <AutoAwesomeIcon/>}
186
+ {inferring ? <CircularProgress size={"small"}/> : <AutorenewIcon/>}
183
187
  Infer values from data
184
188
  </Button>}
185
189
  </div>
@@ -263,7 +267,7 @@ const EnumEntry = React.memo(
263
267
  size="small"
264
268
  autoFocus={autoFocus}
265
269
  autoComplete="off"
266
- endAdornment={inferredEntry && <AutoAwesomeIcon size={"small"}/>}
270
+ endAdornment={inferredEntry && <AutorenewIcon size={"small"}/>}
267
271
  error={Boolean(entryError?.label)}/>
268
272
 
269
273
  {!disabled &&
@@ -324,7 +328,7 @@ function EnumEntryDialog({
324
328
  open={open}
325
329
  onOpenChange={(open) => !open ? onClose() : undefined}
326
330
  >
327
-
331
+ <DialogTitle hidden>Enum form dialog</DialogTitle>
328
332
  <DialogContent>
329
333
  {index !== undefined &&
330
334
  <div>
@@ -1,9 +1,10 @@
1
- import { EntityCollection, useSnackbarController } from "@firecms/core";
2
- import { Button, ContentCopyIcon, Dialog, DialogActions, DialogContent, Typography, } from "@firecms/ui";
1
+ import { EntityCollection, isEmptyObject, useSnackbarController } from "@firecms/core";
2
+ import { Button, ContentCopyIcon, Dialog, DialogActions, DialogContent, DialogTitle, Typography, } from "@firecms/ui";
3
3
  import React from "react";
4
4
  import JSON5 from "json5";
5
5
  import { Highlight, themes } from "prism-react-renderer"
6
6
  import { camelCase } from "./utils/strings";
7
+ import { clone } from "@firecms/formex";
7
8
 
8
9
  export function GetCodeDialog({
9
10
  collection,
@@ -14,15 +15,14 @@ export function GetCodeDialog({
14
15
  const snackbarController = useSnackbarController();
15
16
 
16
17
  const code = collection
17
- ? "import { EntityCollection } from \"@firecms/core\";\n\nconst " + (collection?.name ? camelCase(collection.name) : "my") + "Collection:EntityCollection = " + JSON5.stringify(collectionToCode(collection), null, "\t")
18
+ ? "import { EntityCollection } from \"@firecms/core\";\n\nconst " + (collection?.name ? camelCase(collection.name) : "my") + "Collection:EntityCollection = " + JSON5.stringify(collectionToCode({ ...collection }), null, "\t")
18
19
  : "No collection selected";
19
20
  return <Dialog open={open}
20
21
  onOpenChange={onOpenChange}
21
22
  maxWidth={"4xl"}>
23
+ <DialogTitle variant={"h6"}>Code for {collection.name}</DialogTitle>
22
24
  <DialogContent>
23
- <Typography variant={"h6"} className={"my-4"}>
24
- Code for {collection.name}
25
- </Typography>
25
+
26
26
  <Typography variant={"body2"} className={"my-4 mb-8"}>
27
27
  If you want to customise the collection in code, you can add this collection code to your CMS
28
28
  app configuration.
@@ -78,24 +78,40 @@ export function GetCodeDialog({
78
78
 
79
79
  function collectionToCode(collection: EntityCollection): object {
80
80
 
81
- const propertyCleanup = (property: any) => {
82
-
83
- const updatedProperty = {
84
- ...property
85
- };
86
-
87
- delete updatedProperty.fromBuilder;
88
- delete updatedProperty.resolved;
89
- delete updatedProperty.propertiesOrder;
90
- delete updatedProperty.editable;
81
+ const propertyCleanup = (value: any): any => {
82
+ if (value === undefined || value === null) {
83
+ return value;
84
+ }
85
+ const valueCopy = clone(value);
86
+ if (typeof valueCopy === "function") {
87
+ return valueCopy;
88
+ }
89
+ if (Array.isArray(valueCopy)) {
90
+ return valueCopy.map((v: any) => propertyCleanup(v));
91
+ }
92
+ if (typeof valueCopy === "object") {
93
+ if (valueCopy === null)
94
+ return valueCopy;
95
+ Object.keys(valueCopy).forEach((key) => {
96
+ if (!isEmptyObject(valueCopy)) {
97
+ const childRes = propertyCleanup(valueCopy[key]);
98
+ if (childRes !== null && childRes !== undefined && childRes !== false && !isEmptyObject(childRes)) {
99
+ valueCopy[key] = childRes;
100
+ } else {
101
+ delete valueCopy[key];
102
+ }
103
+ }
104
+ });
105
+ delete valueCopy.fromBuilder;
106
+ delete valueCopy.resolved;
107
+ delete valueCopy.propertiesOrder;
108
+ delete valueCopy.propertyConfig;
109
+ delete valueCopy.resolvedProperties;
110
+ delete valueCopy.editable;
91
111
 
92
- if (updatedProperty.type === "map") {
93
- return {
94
- ...updatedProperty,
95
- properties: updatedProperty.properties.map(propertyCleanup)
96
- }
97
112
  }
98
- return updatedProperty;
113
+
114
+ return valueCopy;
99
115
  }
100
116
 
101
117
  return {
@@ -111,7 +127,9 @@ function collectionToCode(collection: EntityCollection): object {
111
127
  customId: collection.customId,
112
128
  initialFilter: collection.initialFilter,
113
129
  initialSort: collection.initialSort,
114
- properties: Object.entries(collection.properties ?? {})
130
+ properties: Object.entries({
131
+ ...(collection.properties ?? {})
132
+ })
115
133
  .map(([key, value]) => ({
116
134
  [key]: propertyCleanup(value)
117
135
  }))
@@ -6,7 +6,7 @@ import {
6
6
  ConfirmationDialog,
7
7
  DEFAULT_FIELD_CONFIGS,
8
8
  getFieldConfig,
9
- getFieldId,
9
+ getFieldId, isEmptyObject,
10
10
  isPropertyBuilder,
11
11
  isValidRegExp,
12
12
  mergeDeep,
@@ -31,7 +31,7 @@ import {
31
31
  InfoLabel,
32
32
  Tooltip,
33
33
  Typography,
34
- WarningOffIcon
34
+ WarningIcon
35
35
  } from "@firecms/ui";
36
36
  import { EnumPropertyField } from "./properties/EnumPropertyField";
37
37
  import { StoragePropertyField } from "./properties/StoragePropertyField";
@@ -142,6 +142,7 @@ export const PropertyForm = React.memo(
142
142
  };
143
143
 
144
144
  const formexController = useCreateFormex<PropertyWithId>({
145
+ debugId: "PROPERTY_FORM",
145
146
  initialValues: property
146
147
  ? { id: propertyKey, ...property } as PropertyWithId
147
148
  : initialValue,
@@ -274,7 +275,9 @@ export function PropertyFormDialog({
274
275
  e.stopPropagation();
275
276
  formexRef.current?.handleSubmit(e)
276
277
  }}>
278
+ <DialogTitle hidden>Property edit view</DialogTitle>
277
279
  <DialogContent>
280
+
278
281
  <PropertyForm {...formProps}
279
282
  onDismiss={onCancel}
280
283
  onPropertyChanged={(params) => {
@@ -380,7 +383,7 @@ function PropertyEditFormFields({
380
383
  }, [deferredValues, includeIdAndTitle, propertyNamespace]);
381
384
 
382
385
  useEffect(() => {
383
- if (values?.id && onError) {
386
+ if (values?.id && onError && !isEmptyObject(errors)) {
384
387
  onError(values?.id, propertyNamespace, errors);
385
388
  }
386
389
  }, [errors, propertyNamespace, values?.id]);
@@ -771,7 +774,7 @@ export function WidgetSelectViewItem({
771
774
  <div className={"flex flex-row gap-2 items-center"}>
772
775
  {shouldWarnChangingDataType && <Tooltip
773
776
  title={"This widget uses a different data type than the initially selected widget. This can cause errors with existing data."}>
774
- <WarningOffIcon size="smallest" className={"w-4"}/>
777
+ <WarningIcon size="smallest" className={"w-4"}/>
775
778
  </Tooltip>}
776
779
  <Typography
777
780
  color={shouldWarnChangingDataType ? "secondary" : undefined}>{propertyConfig.name}</Typography>
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  ErrorBoundary,
3
- PropertyConfigBadge,
4
3
  getFieldConfig,
5
4
  isPropertyBuilder,
6
5
  Property,
6
+ PropertyConfigBadge,
7
7
  PropertyOrBuilder,
8
8
  useCustomizationController,
9
9
  } from "@firecms/core";
@@ -12,9 +12,9 @@ import {
12
12
  cardMixin,
13
13
  cardSelectedMixin,
14
14
  cls,
15
+ DoNotDisturbOnIcon,
15
16
  FunctionsIcon,
16
17
  Paper,
17
- RemoveCircleIcon,
18
18
  Typography,
19
19
  } from "@firecms/ui";
20
20
 
@@ -130,10 +130,10 @@ export function NonEditablePropertyPreview({
130
130
  <div className={"relative m-4"}>
131
131
  {propertyConfig && <PropertyConfigBadge propertyConfig={propertyConfig}/>}
132
132
  {!propertyConfig && <div
133
- className={"h-8 w-8 p-1 rounded-full shadow text-white bg-gray-500"}>
133
+ className={"h-8 w-8 p-1 rounded-full shadow text-white bg-surface-500"}>
134
134
  <FunctionsIcon color={"inherit"} size={"medium"}/>
135
135
  </div>}
136
- <RemoveCircleIcon color={"disabled"} size={"small"} className={"absolute -right-2 -top-2"}/>
136
+ <DoNotDisturbOnIcon color={"disabled"} size={"small"} className={"absolute -right-2 -top-2"}/>
137
137
  </div>
138
138
  <Paper
139
139
  className={cls(
@@ -9,7 +9,7 @@ import {
9
9
  PropertiesOrBuilders,
10
10
  PropertyOrBuilder
11
11
  } from "@firecms/core";
12
- import { AutoAwesomeIcon, defaultBorderMixin, DragHandleIcon, IconButton, RemoveIcon, Tooltip } from "@firecms/ui";
12
+ import { AutorenewIcon, defaultBorderMixin, DragHandleIcon, IconButton, RemoveIcon, Tooltip } from "@firecms/ui";
13
13
  import { NonEditablePropertyPreview, PropertyFieldPreview } from "./PropertyFieldPreview";
14
14
  import { DragDropContext, Draggable, DraggableProvided, Droppable } from "@hello-pangea/dnd";
15
15
  import { getFullId, getFullIdPath } from "./util";
@@ -224,7 +224,7 @@ export function PropertyTreeEntry({
224
224
  <div className="absolute top-2 right-2 flex flex-row ">
225
225
 
226
226
  {isPropertyInferred && <Tooltip title={"Inferred property"}>
227
- <AutoAwesomeIcon size="small" className={"p-2"}/>
227
+ <AutorenewIcon size="small" className={"p-2"}/>
228
228
  </Tooltip>}
229
229
 
230
230
  {onPropertyRemove && <Tooltip title={"Remove"}