@firecms/core 3.0.0-canary.257 → 3.0.0-canary.259

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 (39) hide show
  1. package/dist/core/EntityEditViewFormActions.d.ts +1 -1
  2. package/dist/form/EntityFormActions.d.ts +4 -2
  3. package/dist/index.es.js +340 -156
  4. package/dist/index.es.js.map +1 -1
  5. package/dist/index.umd.js +340 -156
  6. package/dist/index.umd.js.map +1 -1
  7. package/dist/types/collections.d.ts +4 -1
  8. package/dist/types/customization_controller.d.ts +8 -0
  9. package/dist/types/entity_actions.d.ts +45 -6
  10. package/dist/types/firecms.d.ts +8 -0
  11. package/dist/types/plugins.d.ts +8 -1
  12. package/dist/util/resolutions.d.ts +2 -1
  13. package/package.json +5 -5
  14. package/src/components/ConfirmationDialog.tsx +1 -0
  15. package/src/components/EntityCollectionTable/EntityCollectionRowActions.tsx +2 -0
  16. package/src/components/EntityCollectionTable/internal/CollectionTableToolbar.tsx +2 -2
  17. package/src/components/EntityCollectionView/EntityCollectionView.tsx +5 -2
  18. package/src/components/EntityCollectionView/EntityCollectionViewActions.tsx +3 -2
  19. package/src/components/HomePage/DefaultHomePage.tsx +48 -33
  20. package/src/components/HomePage/HomePageDnD.tsx +22 -36
  21. package/src/components/HomePage/RenameGroupDialog.tsx +6 -2
  22. package/src/components/UnsavedChangesDialog.tsx +6 -2
  23. package/src/components/common/default_entity_actions.tsx +18 -5
  24. package/src/components/common/useDataSourceTableController.tsx +1 -1
  25. package/src/core/EntityEditView.tsx +35 -12
  26. package/src/core/EntityEditViewFormActions.tsx +154 -29
  27. package/src/core/EntitySidePanel.tsx +1 -1
  28. package/src/core/FireCMS.tsx +2 -0
  29. package/src/form/EntityForm.tsx +32 -6
  30. package/src/form/EntityFormActions.tsx +37 -8
  31. package/src/form/field_bindings/MarkdownEditorFieldBinding.tsx +4 -2
  32. package/src/form/field_bindings/StorageUploadFieldBinding.tsx +1 -1
  33. package/src/types/collections.ts +4 -1
  34. package/src/types/customization_controller.tsx +9 -0
  35. package/src/types/entity_actions.tsx +56 -6
  36. package/src/types/firecms.tsx +9 -0
  37. package/src/types/plugins.tsx +9 -1
  38. package/src/util/join_collections.ts +3 -1
  39. package/src/util/resolutions.ts +13 -1
@@ -5,10 +5,11 @@ import { addRecentId } from "../EntityCollectionView/utils";
5
5
  import { navigateToEntity, resolveDefaultSelectedView } from "../../util";
6
6
 
7
7
  export const editEntityAction: EntityAction = {
8
- icon: <EditIcon/>,
8
+ icon: <EditIcon size={"small"}/>,
9
9
  key: "edit",
10
10
  name: "Edit",
11
11
  collapsed: false,
12
+ isEnabled: ({ entity }) => Boolean(entity),
12
13
  onClick({
13
14
  entity,
14
15
  collection,
@@ -20,6 +21,10 @@ export const editEntityAction: EntityAction = {
20
21
  openEntityMode
21
22
  }): Promise<void> {
22
23
 
24
+ if (!entity) {
25
+ throw new Error("INTERNAL: editEntityAction: Entity is undefined");
26
+ }
27
+
23
28
  highlightEntity?.(entity);
24
29
 
25
30
  context.analyticsController?.onAnalyticsEvent?.("entity_click", {
@@ -57,9 +62,10 @@ export const editEntityAction: EntityAction = {
57
62
  }
58
63
 
59
64
  export const copyEntityAction: EntityAction = {
60
- icon: <FileCopyIcon/>,
65
+ icon: <FileCopyIcon size={"small"}/>,
61
66
  name: "Copy",
62
67
  key: "copy",
68
+ isEnabled: ({ entity }) => Boolean(entity),
63
69
  onClick({
64
70
  entity,
65
71
  collection,
@@ -69,6 +75,9 @@ export const copyEntityAction: EntityAction = {
69
75
  unhighlightEntity,
70
76
  openEntityMode
71
77
  }): Promise<void> {
78
+ if (!entity) {
79
+ throw new Error("INTERNAL: copyEntityAction: Entity is undefined");
80
+ }
72
81
  highlightEntity?.(entity);
73
82
  context.analyticsController?.onAnalyticsEvent?.("copy_entity_click", {
74
83
  path: entity.path,
@@ -94,9 +103,10 @@ export const copyEntityAction: EntityAction = {
94
103
  }
95
104
 
96
105
  export const deleteEntityAction: EntityAction = {
97
- icon: <DeleteIcon/>,
106
+ icon: <DeleteIcon size={"small"}/>,
98
107
  name: "Delete",
99
108
  key: "delete",
109
+ isEnabled: ({ entity }) => Boolean(entity),
100
110
  onClick({
101
111
  entity,
102
112
  fullPath,
@@ -104,8 +114,11 @@ export const deleteEntityAction: EntityAction = {
104
114
  context,
105
115
  selectionController,
106
116
  onCollectionChange,
107
- sideEntityController
117
+ navigateBack
108
118
  }): Promise<void> {
119
+ if (!entity) {
120
+ throw new Error("INTERNAL: deleteEntityAction: Entity is undefined");
121
+ }
109
122
  const { closeDialog } = context.dialogsController.open({
110
123
  key: "delete_entity_dialog_" + entity.id,
111
124
  Component: ({ open }) => {
@@ -123,7 +136,7 @@ export const deleteEntityAction: EntityAction = {
123
136
  });
124
137
  selectionController?.setSelectedEntities(selectionController.selectedEntities.filter(e => e.id !== entity.id));
125
138
  onCollectionChange?.();
126
- sideEntityController?.close();
139
+ navigateBack?.();
127
140
  }}
128
141
  onClose={closeDialog}/>;
129
142
  }
@@ -334,7 +334,7 @@ function encodeFilterAndSort(filterValues?: FilterValues<string>, sortBy?: [stri
334
334
  }
335
335
  if (encodedValue !== undefined) {
336
336
  entries[encodeURIComponent(`${key}_op`)] = encodeURIComponent(op);
337
- entries[encodeURIComponent(`${key}_value`)] = encodeURIComponent(encodedValue.toString());
337
+ entries[encodeURIComponent(`${key}_value`)] = encodedValue ? encodeURIComponent(encodedValue.toString()) : "null";
338
338
  }
339
339
  }
340
340
  });
@@ -1,5 +1,13 @@
1
1
  import React, { useEffect, useMemo, useState } from "react";
2
- import { Entity, EntityCollection, EntityStatus, FireCMSPlugin, FormContext, User } from "../types";
2
+ import {
3
+ Entity,
4
+ EntityCollection,
5
+ EntityStatus,
6
+ FireCMSPlugin,
7
+ FormContext,
8
+ PluginFormActionProps,
9
+ User
10
+ } from "../types";
3
11
 
4
12
  import { CircularProgressCenter, EntityCollectionView, EntityView, ErrorBoundary } from "../components";
5
13
  import {
@@ -162,12 +170,33 @@ export function EntityEditViewInner<M extends Record<string, any>>({
162
170
  setUsedEntity(entity);
163
171
  }, [entity]);
164
172
 
165
- // Instead of using a ref (which does not trigger re-render), we use state for the form context.
166
173
  const [formContext, setFormContext] = useState<FormContext<M> | undefined>(undefined);
167
174
 
168
175
  const largeLayout = useLargeLayout();
169
176
 
170
177
  const customizationController = useCustomizationController();
178
+ const plugins = customizationController.plugins;
179
+ const pluginActionsTop: React.ReactNode[] = [];
180
+
181
+ if (plugins && collection) {
182
+ const actionProps: PluginFormActionProps = {
183
+ entityId,
184
+ parentCollectionIds,
185
+ path,
186
+ status,
187
+ collection,
188
+ context,
189
+ formContext,
190
+ openEntityMode: layout,
191
+ disabled: false
192
+ };
193
+ pluginActionsTop.push(...plugins.map((plugin) => (
194
+ plugin.form?.ActionsTop
195
+ ? <plugin.form.ActionsTop
196
+ key={`actions_${plugin.key}`} {...actionProps} />
197
+ : null
198
+ )).filter(Boolean));
199
+ }
171
200
 
172
201
  const defaultSelectedView = useMemo(() => resolveDefaultSelectedView(
173
202
  collection ? collection.defaultSelectedView : undefined,
@@ -191,8 +220,6 @@ export function EntityEditViewInner<M extends Record<string, any>>({
191
220
  const includeJsonView = collection.includeJsonView === undefined ? true : collection.includeJsonView;
192
221
  const hasAdditionalViews = customViewsCount > 0 || subcollectionsCount > 0 || includeJsonView;
193
222
 
194
- const plugins = customizationController.plugins;
195
-
196
223
  const {
197
224
  resolvedEntityViews,
198
225
  selectedEntityView,
@@ -285,13 +312,6 @@ export function EntityEditViewInner<M extends Record<string, any>>({
285
312
  const subcollectionId = subcollection.id ?? subcollection.path;
286
313
  const newFullPath = usedEntity ? `${path}/${usedEntity?.id}/${removeInitialAndTrailingSlashes(subcollection.path)}` : undefined;
287
314
  const newFullIdPath = fullIdPath ? `${fullIdPath}/${usedEntity?.id}/${removeInitialAndTrailingSlashes(subcollectionId)}` : undefined;
288
- console.debug("Rendering subcollection", {
289
- subcollectionId,
290
- fullIdPath,
291
- newFullPath,
292
- newFullIdPath,
293
- selectedTab
294
- });
295
315
 
296
316
  if (selectedTab !== subcollectionId) return null;
297
317
  return (
@@ -423,17 +443,20 @@ export function EntityEditViewInner<M extends Record<string, any>>({
423
443
  let result = <div className="relative flex flex-col h-full w-full bg-white dark:bg-surface-900">
424
444
 
425
445
  {shouldShowTopBar && <div
426
- className={cls("h-14 flex overflow-visible overflow-x-scroll w-full no-scrollbar h-14 border-b pl-2 pr-2 pt-1 flex items-end bg-surface-50 dark:bg-surface-900", defaultBorderMixin)}>
446
+ className={cls("h-14 items-center flex overflow-visible overflow-x-scroll w-full no-scrollbar h-14 border-b pl-2 pr-2 pt-1 flex bg-surface-50 dark:bg-surface-900", defaultBorderMixin)}>
427
447
 
428
448
  {barActions}
429
449
 
430
450
  <div className={"flex-grow"}/>
431
451
 
452
+ {pluginActionsTop}
453
+
432
454
  {globalLoading && <div className="self-center">
433
455
  <CircularProgress size={"small"}/>
434
456
  </div>}
435
457
 
436
458
  {hasAdditionalViews && <Tabs
459
+ className={"self-end"}
437
460
  value={selectedTab}
438
461
  onValueChange={(value) => {
439
462
  onSideTabClick(value);
@@ -1,10 +1,34 @@
1
1
  import React, { useMemo } from "react";
2
- import { Entity, EntityAction, FireCMSContext, ResolvedEntityCollection, SideEntityController } from "../types";
2
+ import {
3
+ Entity,
4
+ EntityAction,
5
+ EntityActionClickProps,
6
+ FireCMSContext,
7
+ FormContext,
8
+ ResolvedEntityCollection,
9
+ SideEntityController
10
+ } from "../types";
3
11
 
4
12
  import { copyEntityAction, deleteEntityAction } from "../components";
5
- import { canCreateEntity, canDeleteEntity, mergeEntityActions } from "../util";
6
- import { Button, cls, defaultBorderMixin, DialogActions, IconButton, LoadingButton, Typography } from "@firecms/ui";
7
- import { useAuthController, useFireCMSContext, useSideEntityController } from "../hooks";
13
+ import { canCreateEntity, canDeleteEntity, mergeEntityActions, resolveEntityAction } from "../util";
14
+ import {
15
+ Button,
16
+ CircularProgress,
17
+ cls,
18
+ defaultBorderMixin,
19
+ DialogActions,
20
+ IconButton,
21
+ LoadingButton,
22
+ Tooltip,
23
+ Typography
24
+ } from "@firecms/ui";
25
+ import {
26
+ useAuthController,
27
+ useCustomizationController,
28
+ useFireCMSContext,
29
+ useSideEntityController,
30
+ useSnackbarController
31
+ } from "../hooks";
8
32
  import { EntityFormActionsProps } from "../form/EntityFormActions";
9
33
  import { SideDialogController, useSideDialogContext } from "./SideDialogs";
10
34
 
@@ -19,16 +43,21 @@ export function EntityEditViewFormActions({
19
43
  status,
20
44
  pluginActions,
21
45
  openEntityMode,
22
- showDefaultActions = true
46
+ showDefaultActions = true,
47
+ navigateBack,
48
+ formContext
23
49
  }: EntityFormActionsProps) {
24
50
 
25
51
  const authController = useAuthController();
26
52
  const context = useFireCMSContext();
27
53
  const sideEntityController = useSideEntityController();
28
54
  const sideDialogContext = useSideDialogContext();
55
+ const customizationController = useCustomizationController();
29
56
 
30
57
  const entityActions = useMemo((): EntityAction[] => {
31
- const customEntityActions = collection.entityActions
58
+ const customEntityActions = (collection.entityActions ?? [])
59
+ .map(action => resolveEntityAction(action, customizationController.entityActions))
60
+ .filter(Boolean) as EntityAction[];
32
61
  const createEnabled = canCreateEntity(collection, authController, path, null);
33
62
  const deleteEnabled = entity ? canDeleteEntity(collection, authController, path, entity) : false;
34
63
  const actions: EntityAction[] = [];
@@ -39,7 +68,7 @@ export function EntityEditViewFormActions({
39
68
  if (customEntityActions)
40
69
  return mergeEntityActions(actions, customEntityActions);
41
70
  return actions;
42
- }, [authController, collection, path]);
71
+ }, [authController, collection, path, customizationController.entityActions?.length]);
43
72
 
44
73
  const formActions = showDefaultActions ? entityActions.filter(a => a.includeInForm === undefined || a.includeInForm) : [];
45
74
 
@@ -57,6 +86,8 @@ export function EntityEditViewFormActions({
57
86
  sideDialogContext,
58
87
  pluginActions,
59
88
  openEntityMode,
89
+ navigateBack,
90
+ formContext
60
91
  })
61
92
  : buildSideActions({
62
93
  savingError,
@@ -71,6 +102,8 @@ export function EntityEditViewFormActions({
71
102
  status,
72
103
  pluginActions,
73
104
  openEntityMode,
105
+ navigateBack,
106
+ formContext
74
107
  });
75
108
  }
76
109
 
@@ -87,6 +120,8 @@ type ActionsViewProps<M extends object> = {
87
120
  sideDialogContext: SideDialogController,
88
121
  pluginActions?: React.ReactNode[],
89
122
  openEntityMode: "side_panel" | "full_screen";
123
+ navigateBack: () => void;
124
+ formContext: FormContext
90
125
  };
91
126
 
92
127
  function buildBottomActions<M extends object>({
@@ -102,37 +137,48 @@ function buildBottomActions<M extends object>({
102
137
  sideDialogContext,
103
138
  pluginActions,
104
139
  openEntityMode,
140
+ navigateBack,
141
+ formContext
105
142
  }: ActionsViewProps<M>) {
106
143
 
107
144
  const canClose = openEntityMode === "side_panel";
108
- return <DialogActions position={"absolute"}>
145
+ return <DialogActions
146
+ position={"absolute"}>
109
147
  {savingError &&
110
148
  <div className="text-right">
111
149
  <Typography color={"error"}>{savingError.message}</Typography>
112
150
  </div>
113
151
  }
114
- {entity && formActions.length > 0 && <div className="flex-grow flex overflow-auto no-scrollbar">
115
- {formActions.map(action => (
116
- <IconButton
117
- key={action.name}
118
- color="primary"
119
- onClick={(event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
120
- event.stopPropagation();
121
- if (entity)
122
- action.onClick({
123
- entity,
124
- fullPath: collection.path,
125
- collection: collection,
126
- context,
127
- sideEntityController,
128
- openEntityMode: openEntityMode
129
- });
130
- }}>
131
- {action.icon}
132
- </IconButton>
133
- ))}
152
+
153
+ {formActions.length > 0 && <div className="flex-grow flex overflow-auto no-scrollbar">
154
+ {formActions.map(action => {
155
+
156
+ const props = {
157
+ view: "form",
158
+ entity,
159
+ fullPath: collection.path,
160
+ collection: collection,
161
+ context,
162
+ sideEntityController,
163
+ openEntityMode,
164
+ navigateBack,
165
+ formContext
166
+ } satisfies EntityActionClickProps<any>;
167
+
168
+ const isEnabled = !action.isEnabled || action.isEnabled(props);
169
+ return (
170
+ <EntityActionButton
171
+ key={action.key}
172
+ action={action}
173
+ enabled={isEnabled}
174
+ props={props}
175
+ />
176
+ );
177
+ })}
134
178
  </div>}
179
+
135
180
  {pluginActions}
181
+
136
182
  <Button variant="text" disabled={disabled || isSubmitting} type="reset">
137
183
  {status === "existing" ? "Discard" : "Clear"}
138
184
  </Button>
@@ -171,7 +217,10 @@ function buildSideActions<M extends object>({
171
217
  disabled,
172
218
  status,
173
219
  sideDialogContext,
174
- pluginActions
220
+ pluginActions,
221
+ openEntityMode,
222
+ navigateBack,
223
+ formContext
175
224
  }: ActionsViewProps<M>) {
176
225
 
177
226
  return <div
@@ -184,12 +233,33 @@ function buildSideActions<M extends object>({
184
233
  {status === "copy" && "Create copy"}
185
234
  {status === "new" && "Create"}
186
235
  </LoadingButton>
236
+
187
237
  <Button fullWidth={true} variant="text" disabled={disabled || isSubmitting} type="reset">
188
238
  {status === "existing" ? "Discard" : "Clear"}
189
239
  </Button>
190
240
 
191
241
  {pluginActions}
192
242
 
243
+ {formActions.length > 0 && <div className="flex flex-row flex-wrap mt-2">
244
+ {formActions.map(action => {
245
+ const props = {
246
+ view: "form",
247
+ entity,
248
+ fullPath: collection.path,
249
+ collection: collection,
250
+ context,
251
+ sideEntityController,
252
+ openEntityMode,
253
+ navigateBack,
254
+ formContext
255
+ } satisfies EntityActionClickProps<any>;
256
+ const isEnabled = !action.isEnabled || action.isEnabled(props);
257
+ return (
258
+ <EntityActionButton key={action.key} action={action} enabled={isEnabled} props={props}/>
259
+ );
260
+ })}
261
+ </div>}
262
+
193
263
  {savingError &&
194
264
  <div className="text-right">
195
265
  <Typography color={"error"}>{savingError.message}</Typography>
@@ -197,3 +267,58 @@ function buildSideActions<M extends object>({
197
267
  }
198
268
  </div>;
199
269
  }
270
+
271
+ function EntityActionButton({
272
+ action,
273
+ enabled,
274
+ props
275
+ }: {
276
+ action: EntityAction,
277
+ enabled: boolean,
278
+ props: EntityActionClickProps<any, any>
279
+ }) {
280
+ const snackbarController = useSnackbarController();
281
+ const [loading, setLoading] = React.useState(false);
282
+ return <Tooltip
283
+ title={action.name}>
284
+ <IconButton
285
+ color="primary"
286
+ disabled={!enabled}
287
+ onClick={(event) => {
288
+ console.debug("Executing action", action.key, props);
289
+ try {
290
+ event.stopPropagation();
291
+ if (props.entity) {
292
+ const onClick = action.onClick(props);
293
+ // If the action returns a promise, we can handle it
294
+ if (onClick instanceof Promise) {
295
+ setLoading(true);
296
+ onClick
297
+ .catch((error) => {
298
+ console.error("Error executing action", action.key, error);
299
+ snackbarController.open({
300
+ message: `Error executing action: ${error.message}`,
301
+ type: "error"
302
+ })
303
+ })
304
+ .finally(() => setLoading(false));
305
+ } else {
306
+ snackbarController.open({
307
+ message: `Action ${action.name} executed successfully`,
308
+ type: "success"
309
+ });
310
+ }
311
+
312
+ }
313
+ } catch (e: any) {
314
+ console.error("Error executing action", action.key, e);
315
+ snackbarController.open({
316
+ message: `Error executing action: ${e.message}`,
317
+ type: "error"
318
+ });
319
+ }
320
+ }}>
321
+ {loading ? <CircularProgress size={"smallest"}/> : action.icon}
322
+ </IconButton>
323
+ </Tooltip>;
324
+ }
@@ -76,7 +76,7 @@ export function EntitySidePanel(props: EntitySidePanelProps) {
76
76
  return navigationController.getParentCollectionIds(path);
77
77
  }, [navigationController, path]);
78
78
 
79
- const collection = props.collection ?? navigationController.getCollection(path);
79
+ const collection = navigationController.getCollection(fullIdPath ?? path) ?? props.collection;
80
80
 
81
81
  useEffect(() => {
82
82
  function beforeunload(e: any) {
@@ -48,6 +48,7 @@ export function FireCMS<USER extends User>(props: FireCMSProps<USER>) {
48
48
  onAnalyticsEvent,
49
49
  propertyConfigs,
50
50
  entityViews,
51
+ entityActions,
51
52
  components,
52
53
  navigationController,
53
54
  apiKey
@@ -72,6 +73,7 @@ export function FireCMS<USER extends User>(props: FireCMSProps<USER>) {
72
73
  entityLinkBuilder,
73
74
  plugins,
74
75
  entityViews: entityViews ?? [],
76
+ entityActions: entityActions ?? [],
75
77
  propertyConfigs: propertyConfigs ?? {},
76
78
  components
77
79
  };
@@ -32,7 +32,8 @@ import {
32
32
  useAuthController,
33
33
  useCustomizationController,
34
34
  useDataSource,
35
- useFireCMSContext,
35
+ useFireCMSContext, useNavigationController,
36
+ useSideEntityController,
36
37
  useSnackbarController
37
38
  } from "../hooks";
38
39
  import { Alert, CheckIcon, Chip, cls, EditIcon, NotesIcon, paperMixin, Tooltip, Typography } from "@firecms/ui";
@@ -121,11 +122,23 @@ export function EntityForm<M extends Record<string, any>>({
121
122
  children
122
123
  }: EntityFormProps<M>) {
123
124
 
124
-
125
125
  if (collection.customId && collection.formAutoSave) {
126
126
  console.warn(`The collection ${collection.path} has customId and formAutoSave enabled. This is not supported and formAutoSave will be ignored`);
127
127
  }
128
128
 
129
+
130
+ const sideEntityController = useSideEntityController();
131
+ const navigationController = useNavigationController();
132
+
133
+ const navigateBack = useCallback(() => {
134
+ if (openEntityMode === "side_panel") {
135
+ // If we are in side panel mode, we close the side panel
136
+ sideEntityController.close();
137
+ } else {
138
+ window.history.back();
139
+ }
140
+ }, []);
141
+
129
142
  const authController = useAuthController();
130
143
  const [status, setStatus] = useState<EntityStatus>(initialStatus);
131
144
 
@@ -436,14 +449,16 @@ export function EntityForm<M extends Record<string, any>>({
436
449
  const plugins = customizationController.plugins;
437
450
 
438
451
  const actionsDisabled = disabled || formex.isSubmitting || (status === "existing" && !formex.dirty) || Boolean(disabledProp);
452
+ const parentCollectionIds = navigationController.getParentCollectionIds(path);
453
+
439
454
  if (plugins && collection) {
440
455
  const actionProps: PluginFormActionProps = {
441
456
  entityId,
457
+ parentCollectionIds,
442
458
  path,
443
459
  status,
444
- collection: collection,
460
+ collection,
445
461
  context,
446
- currentEntityId: entityId,
447
462
  formContext,
448
463
  openEntityMode,
449
464
  disabled: actionsDisabled,
@@ -628,7 +643,13 @@ export function EntityForm<M extends Record<string, any>>({
628
643
  variant={"h4"}>
629
644
  {title ?? collection.singularName ?? collection.name}
630
645
  </Typography>
631
- {showEntityPath && <Alert color={"base"} className={"w-full"} size={"small"}>
646
+
647
+ {!entity?.values && initialStatus === "existing" &&
648
+ <Alert color={"warning"} size={"small"} outerClassName={"w-full mb-4 text-xs"}>
649
+ This entity does not exist in the database
650
+ </Alert>}
651
+
652
+ {showEntityPath && <Alert color={"base"} outerClassName={"w-full"} size={"small"}>
632
653
  <code
633
654
  className={"text-xs select-all text-text-secondary dark:text-text-secondary-dark"}>
634
655
  {entity?.path ?? path}/{entityId}
@@ -638,6 +659,10 @@ export function EntityForm<M extends Record<string, any>>({
638
659
 
639
660
  {children}
640
661
 
662
+ {initialEntityId && !entity && initialStatus !== "new" && <Alert color={"info"} size={"small"}>
663
+ This entity does not exist in the database
664
+ </Alert>}
665
+
641
666
  {!Builder && !collection.hideIdFromForm &&
642
667
  <CustomIdField customId={collection.customId}
643
668
  entityId={entityId}
@@ -668,7 +693,6 @@ export function EntityForm<M extends Record<string, any>>({
668
693
  throw Error("INTERNAL: Collection and path must be defined in form context");
669
694
  }
670
695
 
671
-
672
696
  const dialogActions = <EntityFormActionsComponent
673
697
  collection={resolvedCollection}
674
698
  path={path}
@@ -683,6 +707,8 @@ export function EntityForm<M extends Record<string, any>>({
683
707
  pluginActions={pluginActions ?? []}
684
708
  openEntityMode={openEntityMode}
685
709
  showDefaultActions={showDefaultActions}
710
+ navigateBack={navigateBack}
711
+ formContext={formContext}
686
712
  />;
687
713
 
688
714
  return (