@firecms/core 3.0.0-canary.197 → 3.0.0-canary.199

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.
@@ -1,6 +1,7 @@
1
1
  import { EntityCollection } from "./collections";
2
2
  import { ResolvedEntityCollection } from "./resolved_entities";
3
3
  import { Entity } from "./entities";
4
+ import { EntityFormProps } from "../form";
4
5
  /**
5
6
  * Props used to open a side dialog
6
7
  * @group Hooks and utilities
@@ -55,6 +56,10 @@ export interface EntitySidePanelProps<M extends Record<string, any> = any> {
55
56
  * Should this panel close when saving
56
57
  */
57
58
  closeOnSave?: boolean;
59
+ /**
60
+ * Override some form properties
61
+ */
62
+ formProps?: Partial<EntityFormProps<M>>;
58
63
  }
59
64
  /**
60
65
  * Controller to open the side dialog displaying entity forms
@@ -18,6 +18,7 @@ export interface NavigationViewEntityCustomInternal<M extends Record<string, any
18
18
  type: "custom_view";
19
19
  path: string;
20
20
  fullPath: string;
21
+ entityId: string;
21
22
  view: EntityCustomView<M>;
22
23
  }
23
24
  export declare function getNavigationEntriesFromPath(props: {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@firecms/core",
3
3
  "type": "module",
4
- "version": "3.0.0-canary.197",
4
+ "version": "3.0.0-canary.199",
5
5
  "description": "Awesome Firebase/Firestore-based headless open-source CMS",
6
6
  "funding": {
7
7
  "url": "https://github.com/sponsors/firecmsco"
@@ -50,9 +50,9 @@
50
50
  "./package.json": "./package.json"
51
51
  },
52
52
  "dependencies": {
53
- "@firecms/editor": "^3.0.0-canary.197",
54
- "@firecms/formex": "^3.0.0-canary.197",
55
- "@firecms/ui": "^3.0.0-canary.197",
53
+ "@firecms/editor": "^3.0.0-canary.199",
54
+ "@firecms/formex": "^3.0.0-canary.199",
55
+ "@firecms/ui": "^3.0.0-canary.199",
56
56
  "@hello-pangea/dnd": "^17.0.0",
57
57
  "@radix-ui/react-portal": "^1.1.3",
58
58
  "clsx": "^2.1.1",
@@ -104,7 +104,7 @@
104
104
  "dist",
105
105
  "src"
106
106
  ],
107
- "gitHead": "b7dbb57f47265b42093d962e8d1cd6821a11c6d2",
107
+ "gitHead": "c61e0a8c9aaf3e671612490547db2254b4729b50",
108
108
  "publishConfig": {
109
109
  "access": "public"
110
110
  },
@@ -348,7 +348,7 @@ export const EntityCollectionView = React.memo(
348
348
  const updatedValues = setIn({ ...entity.values }, propertyKey, value);
349
349
 
350
350
  const saveProps: SaveEntityProps = {
351
- path: fullPath,
351
+ path: entity.path ?? fullPath,
352
352
  entityId: entity.id,
353
353
  values: updatedValues,
354
354
  previousValues: entity.values,
@@ -13,7 +13,7 @@ import {
13
13
  } from "../hooks";
14
14
  import { CircularProgress, cls, defaultBorderMixin, Tab, Tabs, Typography } from "@firecms/ui";
15
15
  import { getEntityFromCache } from "../util/entity_cache";
16
- import { EntityForm, FormLayoutInner } from "../form";
16
+ import { EntityForm, EntityFormProps, FormLayoutInner } from "../form";
17
17
  import { EntityEditViewFormActions } from "./EntityEditViewFormActions";
18
18
 
19
19
  const MAIN_TAB_VALUE = "main_##Q$SC^#S6";
@@ -47,6 +47,7 @@ export interface EntityEditViewProps<M extends Record<string, any>> {
47
47
  onTabChange?: (props: OnTabChangeParams<M>) => void;
48
48
  layout?: "side_panel" | "full_screen";
49
49
  barActions?: React.ReactNode;
50
+ formProps?: Partial<EntityFormProps<M>>
50
51
  }
51
52
 
52
53
  /**
@@ -172,6 +173,7 @@ export function EntityEditViewInner<M extends Record<string, any>>({
172
173
  barActions,
173
174
  status,
174
175
  setStatus,
176
+ formProps,
175
177
  }: EntityEditViewProps<M> & {
176
178
  entity?: Entity<M>,
177
179
  cachedDirtyValues?: Partial<M>, // dirty cached entity in memory
@@ -331,20 +333,34 @@ export function EntityEditViewInner<M extends Record<string, any>>({
331
333
  path={path}
332
334
  entityId={entityId ?? usedEntity?.id}
333
335
  onValuesModified={onValuesModified}
334
- onSaved={onSaved ? (params) => onSaved({
335
- ...params,
336
- selectedTab: MAIN_TAB_VALUE === selectedTab ? undefined : selectedTab,
337
- }) : undefined}
338
336
  entity={entity}
339
- cachedDirtyValues={cachedDirtyValues}
337
+ initialDirtyValues={cachedDirtyValues}
340
338
  openEntityMode={layout}
341
- onFormContextReady={setFormContext}
342
339
  forceActionsAtTheBottom={actionsAtTheBottom}
343
340
  initialStatus={status}
344
- onStatusChange={setStatus}
345
- className={!mainViewVisible ? "hidden" : ""}
341
+ className={cls(!mainViewVisible ? "hidden" : "", formProps?.className)}
346
342
  EntityFormActionsComponent={EntityEditViewFormActions}
347
- onEntityChange={setUsedEntity}
343
+ {...formProps}
344
+ onEntityChange={(entity) => {
345
+ setUsedEntity(entity);
346
+ formProps?.onEntityChange?.(entity);
347
+ }}
348
+ onStatusChange={(status) => {
349
+ setStatus(status);
350
+ formProps?.onStatusChange?.(status);
351
+ }}
352
+ onFormContextReady={(formContext) => {
353
+ setFormContext(formContext);
354
+ formProps?.onFormContextReady?.(formContext);
355
+ }}
356
+ onSaved={(params) => {
357
+ const res = {
358
+ ...params,
359
+ selectedTab: MAIN_TAB_VALUE === selectedTab ? undefined : selectedTab,
360
+ };
361
+ onSaved?.(res);
362
+ formProps?.onSaved?.(res);
363
+ }}
348
364
  />;
349
365
 
350
366
  const subcollectionTabs = subcollections && subcollections.map((subcollection) =>
@@ -18,7 +18,8 @@ export function EntityEditViewFormActions({
18
18
  disabled,
19
19
  status,
20
20
  pluginActions,
21
- openEntityMode
21
+ openEntityMode,
22
+ showDefaultActions = true
22
23
  }: EntityFormActionsProps) {
23
24
 
24
25
  const authController = useAuthController();
@@ -40,7 +41,7 @@ export function EntityEditViewFormActions({
40
41
  return actions;
41
42
  }, [authController, collection, path]);
42
43
 
43
- const formActions = entityActions.filter(a => a.includeInForm === undefined || a.includeInForm);
44
+ const formActions = showDefaultActions ? entityActions.filter(a => a.includeInForm === undefined || a.includeInForm) : [];
44
45
 
45
46
  return layout === "bottom"
46
47
  ? buildBottomActions({
@@ -55,7 +56,7 @@ export function EntityEditViewFormActions({
55
56
  status,
56
57
  sideDialogContext,
57
58
  pluginActions,
58
- openEntityMode
59
+ openEntityMode,
59
60
  })
60
61
  : buildSideActions({
61
62
  savingError,
@@ -69,7 +70,7 @@ export function EntityEditViewFormActions({
69
70
  disabled,
70
71
  status,
71
72
  pluginActions,
72
- openEntityMode
73
+ openEntityMode,
73
74
  });
74
75
  }
75
76
 
@@ -100,7 +101,7 @@ function buildBottomActions<M extends object>({
100
101
  status,
101
102
  sideDialogContext,
102
103
  pluginActions,
103
- openEntityMode
104
+ openEntityMode,
104
105
  }: ActionsViewProps<M>) {
105
106
 
106
107
  const canClose = openEntityMode === "side_panel";
@@ -33,8 +33,6 @@ export function EntitySidePanel(props: EntitySidePanelProps) {
33
33
  const navigationController = useNavigationController();
34
34
  const sideDialogsController = useSideDialogContext();
35
35
 
36
- console.log("sideDialogsController", sideDialogsController);
37
-
38
36
  const onClose = () => {
39
37
  if (props.onClose) {
40
38
  props.onClose();
@@ -153,6 +151,7 @@ export function EntitySidePanel(props: EntitySidePanelProps) {
153
151
  collection
154
152
  });
155
153
  }}
154
+ formProps={props.formProps}
156
155
  />
157
156
  </ErrorBoundary>
158
157
 
@@ -25,11 +25,9 @@ import {
25
25
 
26
26
  import {
27
27
  saveEntityWithCallbacks,
28
- useAuthController,
29
28
  useCustomizationController,
30
29
  useDataSource,
31
- useFireCMSContext, useSideDialogsController,
32
- useSideEntityController,
30
+ useFireCMSContext,
33
31
  useSnackbarController
34
32
  } from "../hooks";
35
33
  import { Alert, CheckIcon, Chip, cls, EditIcon, NotesIcon, paperMixin, Tooltip, Typography } from "@firecms/ui";
@@ -42,7 +40,6 @@ import { CustomIdField } from "../form/components/CustomIdField";
42
40
  import { ErrorFocus } from "../form/components/ErrorFocus";
43
41
  import { CustomFieldValidator, getYupEntitySchema } from "../form/validation";
44
42
  import { EntityFormActions, EntityFormActionsProps } from "./EntityFormActions";
45
- import { useSideDialogContext } from "../core";
46
43
 
47
44
  export type OnUpdateParams = {
48
45
  entity: Entity<any>,
@@ -53,7 +50,7 @@ export type OnUpdateParams = {
53
50
  collection: EntityCollection<any>
54
51
  };
55
52
 
56
- type EntityFormProps<M extends Record<string, any>> = {
53
+ export type EntityFormProps<M extends Record<string, any>> = {
57
54
  path: string;
58
55
  collection: EntityCollection<M>;
59
56
  entityId?: string;
@@ -62,7 +59,7 @@ type EntityFormProps<M extends Record<string, any>> = {
62
59
  onIdChange?: (id: string) => void;
63
60
  onValuesModified?: (modified: boolean) => void;
64
61
  onSaved?: (params: OnUpdateParams) => void;
65
- cachedDirtyValues?: Partial<M>; // dirty cached entity in memory
62
+ initialDirtyValues?: Partial<M>; // dirty cached entity in memory
66
63
  onFormContextReady?: (formContext: FormContext) => void;
67
64
  forceActionsAtTheBottom?: boolean;
68
65
  className?: string;
@@ -71,6 +68,16 @@ type EntityFormProps<M extends Record<string, any>> = {
71
68
  onEntityChange?: (entity: Entity<M>) => void;
72
69
  formex?: FormexController<M>;
73
70
  openEntityMode?: "side_panel" | "full_screen";
71
+ /**
72
+ * Include the copy and delete actions in the form
73
+ */
74
+ showDefaultActions?: boolean;
75
+
76
+ /**
77
+ * Display the entity path in the form
78
+ */
79
+ showEntityPath?: boolean;
80
+
74
81
  EntityFormActionsComponent?: React.FC<EntityFormActionsProps>;
75
82
  };
76
83
 
@@ -82,7 +89,7 @@ export function EntityForm<M extends Record<string, any>>({
82
89
  onIdChange,
83
90
  onSaved,
84
91
  entity,
85
- cachedDirtyValues,
92
+ initialDirtyValues,
86
93
  onFormContextReady,
87
94
  forceActionsAtTheBottom,
88
95
  initialStatus,
@@ -91,7 +98,9 @@ export function EntityForm<M extends Record<string, any>>({
91
98
  onEntityChange,
92
99
  openEntityMode = "full_screen",
93
100
  formex: formexProp,
94
- EntityFormActionsComponent = EntityFormActions
101
+ EntityFormActionsComponent = EntityFormActions,
102
+ showDefaultActions = true,
103
+ showEntityPath = true
95
104
  }: EntityFormProps<M>) {
96
105
 
97
106
  if (collection.customId && collection.formAutoSave) {
@@ -186,8 +195,8 @@ export function EntityForm<M extends Record<string, any>>({
186
195
  };
187
196
 
188
197
  const formex: FormexController<M> = formexProp ?? useCreateFormex<M>({
189
- initialValues: (cachedDirtyValues ?? getInitialEntityValues(collection, path, status, entity)) as M,
190
- initialDirty: Boolean(cachedDirtyValues),
198
+ initialValues: (initialDirtyValues ?? getInitialEntityValues(collection, path, status, entity)) as M,
199
+ initialDirty: Boolean(initialDirtyValues),
191
200
  onSubmit,
192
201
  onReset: () => {
193
202
  clearDirtyCache();
@@ -485,77 +494,76 @@ export function EntityForm<M extends Record<string, any>>({
485
494
  const formFieldKeys = getFormFieldKeys(resolvedCollection);
486
495
 
487
496
  const formFields = () => (
488
- <FormLayout>
489
- {formFieldKeys.map((key) => {
490
- const property = resolvedCollection.properties[key];
491
- if (property) {
492
- const underlyingValueHasChanged: boolean =
493
- !!underlyingChanges &&
494
- Object.keys(underlyingChanges).includes(key) &&
495
- formex.touched[key];
496
- const disabled = (!autoSave && formex.isSubmitting) || isReadOnly(property) || Boolean(property.disabled);
497
- const hidden = isHidden(property);
498
- if (hidden) return null;
499
- const widthPercentage = property.widthPercentage ?? 100;
500
- const cmsFormFieldProps: PropertyFieldBindingProps<any, M> = {
501
- propertyKey: key,
502
- disabled,
503
- property,
504
- includeDescription: property.description || property.longDescription,
505
- underlyingValueHasChanged: underlyingValueHasChanged && !autoSave,
506
- context: formContext,
507
- partOfArray: false,
508
- minimalistView: false,
509
- autoFocus: false
510
- };
511
-
512
- return (
513
- <FormEntry propertyKey={key}
514
- widthPercentage={widthPercentage}
515
- key={`field_${key}`}>
516
- <PropertyFieldBinding {...cmsFormFieldProps} />
517
- </FormEntry>
518
- );
519
- }
497
+ <FormLayout>
498
+ {formFieldKeys.map((key) => {
499
+ const property = resolvedCollection.properties[key];
500
+ if (property) {
501
+ const underlyingValueHasChanged: boolean =
502
+ !!underlyingChanges &&
503
+ Object.keys(underlyingChanges).includes(key) &&
504
+ formex.touched[key];
505
+ const disabled = (!autoSave && formex.isSubmitting) || isReadOnly(property) || Boolean(property.disabled);
506
+ const hidden = isHidden(property);
507
+ if (hidden) return null;
508
+ const widthPercentage = property.widthPercentage ?? 100;
509
+ const cmsFormFieldProps: PropertyFieldBindingProps<any, M> = {
510
+ propertyKey: key,
511
+ disabled,
512
+ property,
513
+ includeDescription: property.description || property.longDescription,
514
+ underlyingValueHasChanged: underlyingValueHasChanged && !autoSave,
515
+ context: formContext,
516
+ partOfArray: false,
517
+ minimalistView: false,
518
+ autoFocus: false
519
+ };
520
+
521
+ return (
522
+ <FormEntry propertyKey={key}
523
+ widthPercentage={widthPercentage}
524
+ key={`field_${key}`}>
525
+ <PropertyFieldBinding {...cmsFormFieldProps} />
526
+ </FormEntry>
527
+ );
528
+ }
520
529
 
521
- const additionalField = resolvedCollection.additionalFields?.find(f => f.key === key);
522
- if (additionalField && entity) {
523
- const Builder = additionalField.Builder;
524
- if (!Builder && !additionalField.value) {
525
- throw new Error("When using additional fields you need to provide a Builder or a value");
526
- }
527
- const child = Builder
528
- ? <Builder entity={entity} context={context}/>
529
- : <div className={"w-full"}>
530
- {additionalField.value?.({
531
- entity,
532
- context
533
- })?.toString()}
534
- </div>;
535
-
536
- return (
537
- <div key={`additional_${key}`} className={"w-full"}>
538
- <LabelWithIconAndTooltip
539
- propertyKey={key}
540
- icon={<NotesIcon size={"small"}/>}
541
- title={additionalField.name}
542
- className={"text-text-secondary dark:text-text-secondary-dark ml-3.5"}/>
543
- <div
544
- className={cls(paperMixin, "w-full min-h-14 p-4 md:p-6 overflow-x-scroll no-scrollbar")}>
545
- <ErrorBoundary>
546
- {child}
547
- </ErrorBoundary>
548
- </div>
549
- </div>
550
- );
530
+ const additionalField = resolvedCollection.additionalFields?.find(f => f.key === key);
531
+ if (additionalField && entity) {
532
+ const Builder = additionalField.Builder;
533
+ if (!Builder && !additionalField.value) {
534
+ throw new Error("When using additional fields you need to provide a Builder or a value");
551
535
  }
536
+ const child = Builder
537
+ ? <Builder entity={entity} context={context}/>
538
+ : <div className={"w-full"}>
539
+ {additionalField.value?.({
540
+ entity,
541
+ context
542
+ })?.toString()}
543
+ </div>;
544
+
545
+ return (
546
+ <div key={`additional_${key}`} className={"w-full"}>
547
+ <LabelWithIconAndTooltip
548
+ propertyKey={key}
549
+ icon={<NotesIcon size={"small"}/>}
550
+ title={additionalField.name}
551
+ className={"text-text-secondary dark:text-text-secondary-dark ml-3.5"}/>
552
+ <div
553
+ className={cls(paperMixin, "w-full min-h-14 p-4 md:p-6 overflow-x-scroll no-scrollbar")}>
554
+ <ErrorBoundary>
555
+ {child}
556
+ </ErrorBoundary>
557
+ </div>
558
+ </div>
559
+ );
560
+ }
552
561
 
553
- console.warn(`Property ${key} not found in collection ${resolvedCollection.name} in properties or additional fields. Skipping.`);
554
- return null;
555
- }).filter(Boolean)}
556
- </FormLayout>
557
- )
558
- ;
562
+ console.warn(`Property ${key} not found in collection ${resolvedCollection.name} in properties or additional fields. Skipping.`);
563
+ return null;
564
+ }).filter(Boolean)}
565
+ </FormLayout>
566
+ );
559
567
 
560
568
  const formRef = useRef<HTMLDivElement>(null);
561
569
 
@@ -567,12 +575,12 @@ export function EntityForm<M extends Record<string, any>>({
567
575
  variant={"h4"}>
568
576
  {title ?? collection.singularName ?? collection.name}
569
577
  </Typography>
570
- <Alert color={"base"} className={"w-full"} size={"small"}>
578
+ {showEntityPath && <Alert color={"base"} className={"w-full"} size={"small"}>
571
579
  <code
572
580
  className={"text-xs select-all text-text-secondary dark:text-text-secondary-dark"}>
573
581
  {entity?.path ?? path}/{entityId}
574
582
  </code>
575
- </Alert>
583
+ </Alert>}
576
584
  </div>
577
585
 
578
586
  {!collection.hideIdFromForm &&
@@ -608,7 +616,8 @@ export function EntityForm<M extends Record<string, any>>({
608
616
  pluginActions={pluginActions}
609
617
  forceActionsAtTheBottom={forceActionsAtTheBottom}
610
618
  EntityFormActionsComponent={EntityFormActionsComponent}
611
- formContext={formContext}>
619
+ formContext={formContext}
620
+ showDefaultActions={showDefaultActions}>
612
621
  {formView}
613
622
  </FormLayoutInner>
614
623
  );
@@ -661,7 +670,8 @@ export function FormLayoutInner({
661
670
  className,
662
671
  forceActionsAtTheBottom,
663
672
  pluginActions,
664
- EntityFormActionsComponent
673
+ EntityFormActionsComponent,
674
+ showDefaultActions
665
675
  }: {
666
676
  id?: string,
667
677
  formContext: FormContext,
@@ -670,6 +680,7 @@ export function FormLayoutInner({
670
680
  forceActionsAtTheBottom?: boolean,
671
681
  pluginActions?: React.ReactNode[],
672
682
  EntityFormActionsComponent: React.FC<EntityFormActionsProps>;
683
+ showDefaultActions?: boolean;
673
684
  }) {
674
685
 
675
686
  const formex = formContext.formex;
@@ -696,6 +707,7 @@ export function FormLayoutInner({
696
707
  status={status}
697
708
  pluginActions={pluginActions ?? []}
698
709
  openEntityMode={openEntityMode}
710
+ showDefaultActions={showDefaultActions}
699
711
  />;
700
712
 
701
713
  return (
@@ -15,6 +15,7 @@ export interface EntityFormActionsProps {
15
15
  status: "new" | "existing" | "copy";
16
16
  pluginActions: React.ReactNode[];
17
17
  openEntityMode: "side_panel" | "full_screen";
18
+ showDefaultActions?: boolean;
18
19
  }
19
20
 
20
21
  export function EntityFormActions({
@@ -104,12 +104,10 @@ export const useBuildSideEntityController = (navigation: NavigationController,
104
104
  const panelsFromUrl = buildSidePanelsFromUrl(entityOrCollectionPath, navigation.collections ?? [], newFlag);
105
105
  for (let i = 0; i < panelsFromUrl.length; i++) {
106
106
  const props = panelsFromUrl[i];
107
- // setTimeout(() => {
108
107
  if (i === 0)
109
108
  sideDialogsController.replace(propsToSidePanel(props, navigation.buildUrlCollectionPath, navigation.resolveIdsFrom, smallLayout));
110
109
  else
111
110
  sideDialogsController.open(propsToSidePanel(props, navigation.buildUrlCollectionPath, navigation.resolveIdsFrom, smallLayout))
112
- // }, 1);
113
111
  }
114
112
  }
115
113
  initialised.current = true;
@@ -260,6 +258,7 @@ const propsToSidePanel = (props: EntitySidePanelProps,
260
258
  const resolvedPanelProps: EntitySidePanelProps<any> = {
261
259
  ...props,
262
260
  path: resolvedPath,
261
+ formProps: props.formProps
263
262
  };
264
263
 
265
264
  const entityViewWidth = getEntityViewWidth(props, smallLayout);
@@ -107,6 +107,19 @@ export function FireCMSRoute() {
107
107
 
108
108
  }
109
109
 
110
+ function getSelectedTabFromUrl(isNew: boolean, lastCustomView: NavigationViewCollectionInternal<any> | NavigationViewEntityCustomInternal<any> | undefined) {
111
+ if (isNew) {
112
+ return undefined;
113
+ } else if (lastCustomView) {
114
+ if (lastCustomView.type === "custom_view") {
115
+ return lastCustomView.view.key;
116
+ } else if (lastCustomView.type === "collection") {
117
+ return lastCustomView.id ?? lastCustomView.path;
118
+ }
119
+ }
120
+ return undefined;
121
+ }
122
+
110
123
  function EntityFullScreenRoute({
111
124
  pathname,
112
125
  navigationEntries,
@@ -136,7 +149,7 @@ function EntityFullScreenRoute({
136
149
 
137
150
  const entityId = lastEntityEntry?.entityId;
138
151
 
139
- const urlTab = isNew ? undefined : (lastCustomView && "id" in lastCustomView ? lastCustomView?.id : undefined) ?? lastCustomView?.path;
152
+ const urlTab = getSelectedTabFromUrl(isNew, lastCustomView);
140
153
  const [selectedTab, setSelectedTab] = useState<string | undefined>(urlTab);
141
154
 
142
155
  const parentCollectionIds = navigation.getParentCollectionIds(navigationPath);
@@ -1,4 +1,5 @@
1
1
  import React from "react";
2
+ import { EntityFormProps } from "../form";
2
3
 
3
4
  /**
4
5
  * Controller to open the side dialog
@@ -78,4 +79,5 @@ export interface SideDialogPanelProps {
78
79
  * Use this prop to store additional data in the panel
79
80
  */
80
81
  additional?: any;
82
+
81
83
  }
@@ -2,6 +2,7 @@ import { EntityCollection } from "./collections";
2
2
  import { ResolvedEntityCollection } from "./resolved_entities";
3
3
  import { Entity } from "./entities";
4
4
  import { EntityOverrides } from "./entity_overrides";
5
+ import { EntityFormProps } from "../form";
5
6
 
6
7
  /**
7
8
  * Props used to open a side dialog
@@ -66,6 +67,10 @@ export interface EntitySidePanelProps<M extends Record<string, any> = any> {
66
67
  */
67
68
  closeOnSave?: boolean;
68
69
 
70
+ /**
71
+ * Override some form properties
72
+ */
73
+ formProps?: Partial<EntityFormProps<M>>;
69
74
  }
70
75
 
71
76
  /**
@@ -27,6 +27,7 @@ export interface NavigationViewEntityCustomInternal<M extends Record<string, any
27
27
  type: "custom_view";
28
28
  path: string;
29
29
  fullPath: string;
30
+ entityId: string;
30
31
  view: EntityCustomView<M>;
31
32
  }
32
33
 
@@ -88,13 +89,11 @@ export function getNavigationEntriesFromPath(props: {
88
89
  .filter(Boolean)
89
90
  .find((entry) => entry!.key === newPath);
90
91
  if (customView) {
91
- const path = currentFullPath && currentFullPath.length > 0
92
- ? (currentFullPath + "/" + customView.key)
93
- : customView.key;
94
92
  result.push({
95
93
  type: "custom_view",
96
- path,
97
- fullPath: fullPath + "/" + path,
94
+ path: collectionPath,
95
+ entityId: entityId,
96
+ fullPath: fullPath + "/" + customView.key,
98
97
  view: customView
99
98
  });
100
99
  } else if (collection.subcollections) {