@firecms/core 3.0.0-beta.13 → 3.0.0-beta.14

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 (71) hide show
  1. package/dist/components/ArrayContainer.d.ts +7 -12
  2. package/dist/components/EntityPreview.d.ts +4 -2
  3. package/dist/components/SelectableTable/SelectableTable.d.ts +1 -1
  4. package/dist/components/VirtualTable/VirtualTableProps.d.ts +0 -4
  5. package/dist/components/index.d.ts +1 -0
  6. package/dist/form/field_bindings/MapFieldBinding.d.ts +1 -1
  7. package/dist/form/field_bindings/StorageUploadFieldBinding.d.ts +3 -9
  8. package/dist/hooks/useBuildNavigationController.d.ts +2 -9
  9. package/dist/index.es.js +1183 -705
  10. package/dist/index.es.js.map +1 -1
  11. package/dist/index.umd.js +1191 -716
  12. package/dist/index.umd.js.map +1 -1
  13. package/dist/types/collections.d.ts +20 -2
  14. package/dist/types/firecms.d.ts +2 -1
  15. package/dist/types/navigation.d.ts +5 -0
  16. package/dist/types/plugins.d.ts +12 -0
  17. package/dist/types/side_entity_controller.d.ts +4 -0
  18. package/dist/util/callbacks.d.ts +2 -0
  19. package/dist/util/index.d.ts +1 -0
  20. package/package.json +8 -6
  21. package/src/components/ArrayContainer.tsx +409 -294
  22. package/src/components/ClearFilterSortButton.tsx +1 -1
  23. package/src/components/ConfirmationDialog.tsx +9 -9
  24. package/src/components/EntityCollectionTable/PropertyTableCell.tsx +1 -1
  25. package/src/components/EntityCollectionTable/internal/CollectionTableToolbar.tsx +1 -1
  26. package/src/components/EntityCollectionTable/internal/EntityTableCell.tsx +13 -2
  27. package/src/components/EntityCollectionTable/internal/popup_field/PopupFormField.tsx +53 -27
  28. package/src/components/EntityCollectionTable/internal/popup_field/useDraggable.tsx +9 -9
  29. package/src/components/EntityCollectionView/EntityCollectionView.tsx +4 -0
  30. package/src/components/EntityPreview.tsx +18 -14
  31. package/src/components/ErrorView.tsx +1 -1
  32. package/src/components/HomePage/DefaultHomePage.tsx +2 -1
  33. package/src/components/HomePage/NavigationCardBinding.tsx +3 -1
  34. package/src/components/SelectableTable/SelectableTable.tsx +140 -143
  35. package/src/components/VirtualTable/VirtualTable.tsx +8 -30
  36. package/src/components/VirtualTable/VirtualTableProps.tsx +0 -5
  37. package/src/components/VirtualTable/fields/VirtualTableInput.tsx +0 -1
  38. package/src/components/index.tsx +2 -0
  39. package/src/core/EntityEditView.tsx +26 -14
  40. package/src/core/EntitySidePanel.tsx +15 -20
  41. package/src/core/FireCMS.tsx +7 -1
  42. package/src/form/EntityForm.tsx +1 -1
  43. package/src/form/PropertyFieldBinding.tsx +0 -1
  44. package/src/form/components/CustomIdField.tsx +3 -1
  45. package/src/form/components/LabelWithIcon.tsx +1 -1
  46. package/src/form/field_bindings/ArrayOfReferencesFieldBinding.tsx +3 -2
  47. package/src/form/field_bindings/MapFieldBinding.tsx +5 -4
  48. package/src/form/field_bindings/MultiSelectFieldBinding.tsx +1 -1
  49. package/src/form/field_bindings/RepeatFieldBinding.tsx +1 -0
  50. package/src/form/field_bindings/SelectFieldBinding.tsx +2 -1
  51. package/src/form/field_bindings/StorageUploadFieldBinding.tsx +222 -154
  52. package/src/hooks/data/save.ts +0 -6
  53. package/src/hooks/useBuildNavigationController.tsx +30 -16
  54. package/src/internal/useBuildSideEntityController.tsx +1 -1
  55. package/src/preview/components/ImagePreview.tsx +2 -2
  56. package/src/preview/components/ReferencePreview.tsx +1 -1
  57. package/src/preview/property_previews/ArrayOfMapsPreview.tsx +1 -1
  58. package/src/preview/property_previews/MapPropertyPreview.tsx +1 -1
  59. package/src/preview/property_previews/SkeletonPropertyComponent.tsx +1 -1
  60. package/src/preview/property_previews/StringPropertyPreview.tsx +1 -1
  61. package/src/types/collections.ts +24 -2
  62. package/src/types/firecms.tsx +2 -2
  63. package/src/types/navigation.ts +6 -0
  64. package/src/types/plugins.tsx +16 -0
  65. package/src/types/side_entity_controller.tsx +5 -5
  66. package/src/util/callbacks.ts +119 -0
  67. package/src/util/index.ts +1 -0
  68. package/src/util/navigation_utils.ts +70 -55
  69. package/src/util/objects.ts +53 -20
  70. package/dist/components/EntityCollectionTable/internal/popup_field/ElementResizeListener.d.ts +0 -5
  71. package/src/components/EntityCollectionTable/internal/popup_field/ElementResizeListener.tsx +0 -59
@@ -18,7 +18,7 @@ export function ClearFilterSortButton({
18
18
  if ((filterIsSet || sortIsSet) && (tableController.clearFilter || tableController.setSortBy)) {
19
19
  let label;
20
20
  if (filterIsSet && sortIsSet) {
21
- label = "Clear filter and sort";
21
+ label = "Clear filter/sort";
22
22
  } else if (filterIsSet) {
23
23
  label = "Clear filter";
24
24
  } else {
@@ -1,15 +1,15 @@
1
1
  import React from "react";
2
2
 
3
- import { Button, Dialog, DialogActions, DialogContent, DialogTitle, LoadingButton, Typography } from "@firecms/ui";
3
+ import { Button, Dialog, DialogActions, DialogContent, DialogTitle, LoadingButton } from "@firecms/ui";
4
4
 
5
5
  export function ConfirmationDialog({
6
- open,
7
- onAccept,
8
- onCancel,
9
- title,
10
- loading,
11
- body
12
- }: {
6
+ open,
7
+ onAccept,
8
+ onCancel,
9
+ title,
10
+ loading,
11
+ body
12
+ }: {
13
13
  open: boolean,
14
14
  onAccept: () => void,
15
15
  onCancel: () => void,
@@ -38,7 +38,7 @@ export function ConfirmationDialog({
38
38
  type="submit"
39
39
  loading={loading}
40
40
  onClick={onAccept}
41
- >
41
+ autoFocus>
42
42
  Ok
43
43
  </LoadingButton>
44
44
  </DialogActions>
@@ -394,7 +394,7 @@ export const PropertyTableCell = React.memo<PropertyTableCellProps<any>>(
394
394
  size={size}
395
395
  multiselect={true}
396
396
  path={arrayProperty.of.path}
397
- previewProperties={arrayProperty.of.previewProperties}
397
+ previewProperties={arrayProperty.of.previewKeys}
398
398
  title={arrayProperty.name}
399
399
  forceFilter={arrayProperty.of.forceFilter}
400
400
  includeId={arrayProperty.of.includeId}
@@ -55,7 +55,7 @@ export function CollectionTableToolbar({
55
55
  <Tooltip title={"Table row size"} side={"right"} sideOffset={4}>
56
56
  <Select
57
57
  value={size as string}
58
- className="w-16 h-10"
58
+ className="w-16 ml-2"
59
59
  size={"small"}
60
60
  onValueChange={(v) => onSizeChanged(v as CollectionSize)}
61
61
  renderValue={(v) => <div className={"font-medium"}>{v.toUpperCase()}</div>}
@@ -5,6 +5,7 @@ import useMeasure from "react-use-measure";
5
5
  import { cls, DoNotDisturbOnIcon, Tooltip } from "@firecms/ui";
6
6
  import { ErrorBoundary } from "../../../components";
7
7
  import { getRowHeight, TableSize } from "../../common/table_height";
8
+ import { ErrorTooltip } from "../../ErrorTooltip";
8
9
 
9
10
  interface EntityTableCellProps {
10
11
  children: React.ReactNode;
@@ -183,7 +184,7 @@ export const EntityTableCell = React.memo<EntityTableCellProps>(
183
184
  ? "border-primary"
184
185
  : "border-transparent";
185
186
 
186
- return (
187
+ const result = <>
187
188
  <div
188
189
  className={cls(
189
190
  "transition-colors duration-100 ease-in-out",
@@ -241,7 +242,17 @@ export const EntityTableCell = React.memo<EntityTableCellProps>(
241
242
  </div>}
242
243
 
243
244
  </div>
244
- );
245
+ </>;
246
+ if (showError) {
247
+ return (
248
+ <ErrorTooltip
249
+ align={"start"}
250
+ title={error?.message ?? "Error"}>
251
+ {result}
252
+ </ErrorTooltip>
253
+ );
254
+ }
255
+ return result;
245
256
  }, (a, b) => {
246
257
  return a.error === b.error &&
247
258
  a.value === b.value &&
@@ -17,7 +17,6 @@ import { Formex, useCreateFormex } from "@firecms/formex";
17
17
  import { useDraggable } from "./useDraggable";
18
18
  import { CustomFieldValidator, getYupEntitySchema } from "../../../../form/validation";
19
19
  import { useWindowSize } from "./useWindowSize";
20
- import { ElementResizeListener } from "./ElementResizeListener";
21
20
  import { getPropertyInPath, isReadOnly, resolveCollection } from "../../../../util";
22
21
  import { Button, CloseIcon, DialogActions, IconButton, Typography } from "@firecms/ui";
23
22
  import { PropertyFieldBinding, yupToFormErrors } from "../../../../form";
@@ -71,7 +70,7 @@ export function PopupFormFieldLoading<M extends Record<string, any>>({
71
70
  collection: inputCollection
72
71
  }).then(setEntity);
73
72
  }
74
- }, [entityId, inputCollection]);
73
+ }, [entityId, inputCollection, dataSource, path]);
75
74
 
76
75
  if (!entity) return null;
77
76
  return <PopupFormFieldInternal {...{
@@ -147,33 +146,35 @@ export function PopupFormFieldInternal<M extends Record<string, any>>({
147
146
  };
148
147
  }, [cellRect, windowSize.height, windowSize.width]);
149
148
 
150
- const normalizePosition = useCallback(({
151
- x,
152
- y
153
- }: { x: number, y: number }) => {
154
-
155
- const draggableBoundingRect = draggableRef.current?.getBoundingClientRect();
156
- if (!draggableBoundingRect)
157
- throw Error("normalizePosition called before draggableBoundingRect is set");
158
-
149
+ const normalizePosition = useCallback((
150
+ pos: { x: number, y: number },
151
+ draggableBoundingRect: DOMRect,
152
+ currentWindowSize: { width: number, height: number }
153
+ ) => {
154
+ if (!draggableBoundingRect || draggableBoundingRect.width === 0 || draggableBoundingRect.height === 0) {
155
+ return pos;
156
+ }
159
157
  return {
160
- x: Math.max(0, Math.min(x, windowSize.width - draggableBoundingRect.width)),
161
- y: Math.max(0, Math.min(y, windowSize.height - draggableBoundingRect.height))
158
+ x: Math.max(0, Math.min(pos.x, currentWindowSize.width - draggableBoundingRect.width)),
159
+ y: Math.max(0, Math.min(pos.y, currentWindowSize.height - draggableBoundingRect.height))
162
160
  };
163
- }, [windowSize]);
161
+ }, []);
164
162
 
165
- const updatePopupLocation = useCallback((position?: {
163
+ const updatePopupLocation = useCallback((newPositionCandidate?: {
166
164
  x: number,
167
165
  y: number
168
166
  }) => {
169
-
170
167
  const draggableBoundingRect = draggableRef.current?.getBoundingClientRect();
171
- if (!cellRect || !draggableBoundingRect) return;
172
- // const newPosition = normalizePosition(position ?? getInitialLocation());
173
- const newPosition = position ?? normalizePosition(getInitialLocation());
174
- if (!popupLocation || newPosition.x !== popupLocation.x || newPosition.y !== popupLocation.y)
175
- setPopupLocation(newPosition);
176
- }, [cellRect, getInitialLocation, normalizePosition, popupLocation]);
168
+ if (!cellRect || !draggableBoundingRect || draggableBoundingRect.width === 0 || draggableBoundingRect.height === 0) {
169
+ return;
170
+ }
171
+ const basePosition = newPositionCandidate ?? getInitialLocation();
172
+ const newNormalizedPosition = normalizePosition(basePosition, draggableBoundingRect, windowSize);
173
+
174
+ if (!popupLocation || newNormalizedPosition.x !== popupLocation.x || newNormalizedPosition.y !== popupLocation.y) {
175
+ setPopupLocation(newNormalizedPosition);
176
+ }
177
+ }, [cellRect, getInitialLocation, normalizePosition, popupLocation, windowSize]);
177
178
 
178
179
  useDraggable({
179
180
  containerRef: draggableRef,
@@ -192,19 +193,25 @@ export function PopupFormFieldInternal<M extends Record<string, any>>({
192
193
 
193
194
  useLayoutEffect(
194
195
  () => {
196
+ if (!cellRect || initialPositionSet.current) return;
197
+ // Ensure draggableRef is available and has dimensions before initial positioning
195
198
  const draggableBoundingRect = draggableRef.current?.getBoundingClientRect();
196
- if (!cellRect || !draggableBoundingRect || initialPositionSet.current) return;
199
+ if (!draggableBoundingRect || draggableBoundingRect.width === 0 || draggableBoundingRect.height === 0) {
200
+ // If not ready, perhaps wait or log. For now, just return.
201
+ // This might need a retry mechanism or ensure content is rendered first.
202
+ return;
203
+ }
197
204
  updatePopupLocation();
198
205
  initialPositionSet.current = true;
199
206
  },
200
- [cellRect, updatePopupLocation, initialPositionSet.current]
207
+ [cellRect, updatePopupLocation] // Removed initialPositionSet.current from deps as it's a ref
201
208
  );
202
209
 
203
210
  useLayoutEffect(
204
211
  () => {
205
212
  updatePopupLocation(popupLocation);
206
213
  },
207
- [windowSize, cellRect]
214
+ [windowSize, cellRect, updatePopupLocation, popupLocation]
208
215
  );
209
216
 
210
217
  const validationSchema = useMemo(() => {
@@ -218,9 +225,28 @@ export function PopupFormFieldInternal<M extends Record<string, any>>({
218
225
  }, [collection, entityId, propertyKey, customFieldValidator]);
219
226
 
220
227
  const adaptResize = useCallback(() => {
228
+ // When the popup resizes, we want to re-evaluate its position
229
+ // based on its current location and new dimensions.
221
230
  return updatePopupLocation(popupLocation);
222
231
  }, [popupLocation, updatePopupLocation]);
223
232
 
233
+ // Setup ResizeObserver
234
+ useEffect(() => {
235
+ const element = draggableRef.current;
236
+ if (!element) return;
237
+
238
+ const observer = new ResizeObserver(() => {
239
+ adaptResize();
240
+ });
241
+
242
+ observer.observe(element);
243
+
244
+ return () => {
245
+ observer.unobserve(element);
246
+ observer.disconnect();
247
+ };
248
+ }, [adaptResize, draggableRef]);
249
+
224
250
  const saveValue = async (values: M) => {
225
251
  setSavingError(null);
226
252
  if (inputCollection && entity && onCellValueChange && propertyKey) {
@@ -288,7 +314,7 @@ export function PopupFormFieldInternal<M extends Record<string, any>>({
288
314
  underlyingValueHasChanged: false,
289
315
  context: formContext,
290
316
  partOfArray: false,
291
- minimalistView: false,
317
+ minimalistView: true,
292
318
  autoFocus: open
293
319
  }
294
320
  : undefined;
@@ -372,7 +398,7 @@ export function PopupFormFieldInternal<M extends Record<string, any>>({
372
398
  } cursor-grab overflow-visible`}
373
399
  ref={draggableRef}>
374
400
 
375
- <ElementResizeListener onResize={adaptResize}/>
401
+ {/* ElementResizeListener removed from here */}
376
402
 
377
403
  <div
378
404
  className="overflow-hidden">
@@ -1,9 +1,8 @@
1
- import React, { useEffect } from "react";
1
+ import React, { useCallback, useEffect } from "react";
2
2
 
3
3
  interface DraggableProps {
4
4
  containerRef: React.RefObject<HTMLDivElement>,
5
5
  innerRef: React.RefObject<HTMLDivElement>,
6
- // ref: React.RefObject<HTMLDivElement>,
7
6
  x?: number;
8
7
  y?: number;
9
8
  onMove: (params: { x: number, y: number }) => void,
@@ -22,7 +21,7 @@ export function useDraggable({
22
21
 
23
22
  const listeningRef = React.useRef(false);
24
23
 
25
- const onMouseDown = (event: any) => {
24
+ const onMouseDown = useCallback((event: any) => {
26
25
  if (event.button !== 0 || !containerRef.current || event.defaultPrevented || event.innerClicked) {
27
26
  return;
28
27
  }
@@ -39,16 +38,17 @@ export function useDraggable({
39
38
  document.addEventListener("selectstart", onSelect);
40
39
  listeningRef.current = true;
41
40
  // event.stopPropagation();
42
- };
43
- const onMouseDownInner = (event: any) => {
41
+ }, [containerRef, onMove]);
42
+
43
+ const onMouseDownInner = useCallback((event: any) => {
44
44
  // @ts-ignore
45
45
  event.innerClicked = true;
46
- };
46
+ }, [])
47
47
 
48
- const onSelect = (event: any) => {
48
+ const onSelect = useCallback((event: any) => {
49
49
  event.preventDefault()
50
50
  event.stopPropagation();
51
- };
51
+ }, [])
52
52
 
53
53
  const onMouseUp = (event: any) => {
54
54
  document.removeEventListener("mousemove", onMouseMove);
@@ -92,6 +92,6 @@ export function useDraggable({
92
92
  if (innerCurrent)
93
93
  innerCurrent.removeEventListener("mousedown", onMouseDownInner);
94
94
  };
95
- });
95
+ }, [containerRef, innerRef, onMouseDownInner, onMouseDown]);
96
96
 
97
97
  }
@@ -425,6 +425,7 @@ export const EntityCollectionView = React.memo(
425
425
  Builder: ({ entity }) => (
426
426
  <Button color={"primary"}
427
427
  variant={"outlined"}
428
+ className={"max-w-full truncate justify-start"}
428
429
  startIcon={<KeyboardTabIcon size={"small"}/>}
429
430
  onClick={(event: any) => {
430
431
  event.stopPropagation();
@@ -749,10 +750,13 @@ export const EntityCollectionView = React.memo(
749
750
  equal(a.defaultSize, b.defaultSize) &&
750
751
  equal(a.initialFilter, b.initialFilter) &&
751
752
  equal(a.initialSort, b.initialSort) &&
753
+ equal(a.includeJsonView, b.includeJsonView) &&
752
754
  equal(a.textSearchEnabled, b.textSearchEnabled) &&
753
755
  equal(a.additionalFields, b.additionalFields) &&
754
756
  equal(a.sideDialogWidth, b.sideDialogWidth) &&
755
757
  equal(a.openEntityMode, b.openEntityMode) &&
758
+ equal(a.exportable, b.exportable) &&
759
+ equal(a.history, b.history) &&
756
760
  equal(a.forceFilter, b.forceFilter);
757
761
  }) as React.FunctionComponent<EntityCollectionViewProps<any>>
758
762
 
@@ -7,6 +7,7 @@ import {
7
7
  getEntityImagePreviewPropertyKey,
8
8
  getEntityPreviewKeys,
9
9
  getEntityTitlePropertyKey,
10
+ getPropertyInPath,
10
11
  getValueInPath,
11
12
  IconForView,
12
13
  resolveCollection
@@ -26,11 +27,13 @@ export type EntityPreviewProps = {
26
27
  actions?: React.ReactNode,
27
28
  collection?: EntityCollection,
28
29
  hover?: boolean;
29
- previewProperties?: string[],
30
+ previewKeys?: string[],
30
31
  disabled?: boolean,
31
32
  entity: Entity<any>,
32
33
  includeId?: boolean,
34
+ includeTitle?: boolean,
33
35
  includeEntityLink?: boolean,
36
+ includeImage?: boolean,
34
37
  onClick?: (e: React.SyntheticEvent) => void;
35
38
  };
36
39
 
@@ -43,12 +46,14 @@ export function EntityPreview({
43
46
  disabled,
44
47
  hover,
45
48
  collection: collectionProp,
46
- previewProperties,
49
+ previewKeys,
47
50
  onClick,
48
51
  size,
49
52
  includeId = true,
53
+ includeTitle = true,
50
54
  includeEntityLink = true,
51
- entity
55
+ includeImage = true,
56
+ entity,
52
57
  }: EntityPreviewProps) {
53
58
 
54
59
  const authController = useAuthController();
@@ -72,11 +77,11 @@ export function EntityPreview({
72
77
  authController
73
78
  }), [collection]);
74
79
 
75
- const listProperties = useMemo(() => getEntityPreviewKeys(authController, resolvedCollection, customizationController.propertyConfigs, previewProperties, size === "medium" || size === "large" ? 3 : 1),
76
- [previewProperties, resolvedCollection, size]);
80
+ const listProperties = useMemo(() => previewKeys ?? getEntityPreviewKeys(authController, resolvedCollection, customizationController.propertyConfigs, previewKeys, size === "medium" || size === "large" ? 3 : 1),
81
+ [previewKeys, resolvedCollection, size]);
77
82
 
78
- const titleProperty = getEntityTitlePropertyKey(resolvedCollection, customizationController.propertyConfigs);
79
- const imagePropertyKey = getEntityImagePreviewPropertyKey(resolvedCollection);
83
+ const titleProperty = includeTitle ? getEntityTitlePropertyKey(resolvedCollection, customizationController.propertyConfigs) : undefined;
84
+ const imagePropertyKey = includeImage ? getEntityImagePreviewPropertyKey(resolvedCollection) : undefined;
80
85
  const imageProperty = imagePropertyKey ? resolvedCollection.properties[imagePropertyKey] : undefined;
81
86
  const usedImageProperty = imageProperty && "of" in imageProperty ? imageProperty.of : imageProperty;
82
87
  const restProperties = listProperties.filter(p => p !== titleProperty && p !== imagePropertyKey);
@@ -103,9 +108,7 @@ export function EntityPreview({
103
108
  </div>
104
109
 
105
110
 
106
- <div className={"flex flex-col grow-1 w-full m-1 shrink-1"} style={{
107
- "maxWidth": "calc(100% - 96px)"
108
- }}>
111
+ <div className={"flex flex-col grow w-full m-1 shrink min-w-0"}>
109
112
 
110
113
  {size !== "small" && includeId && (
111
114
  entity
@@ -135,9 +138,10 @@ export function EntityPreview({
135
138
  )}
136
139
 
137
140
  {restProperties && restProperties.map((key) => {
138
- const childProperty = resolvedCollection.properties[key as string];
141
+ const childProperty = getPropertyInPath(resolvedCollection.properties, key);
139
142
  if (!childProperty) return null;
140
143
 
144
+ const valueInPath = getValueInPath(entity.values, key);
141
145
  return (
142
146
  <div key={"ref_prev_" + key}
143
147
  className={cls("truncate", restProperties.length > 1 ? "my-0.5" : "my-0")}>
@@ -145,7 +149,7 @@ export function EntityPreview({
145
149
  entity
146
150
  ? <PropertyPreview
147
151
  propertyKey={key as string}
148
- value={getValueInPath(entity.values, key)}
152
+ value={valueInPath}
149
153
  property={childProperty as ResolvedProperty}
150
154
  size={"small"}/>
151
155
  : <SkeletonPropertyComponent
@@ -162,7 +166,7 @@ export function EntityPreview({
162
166
  <Tooltip title={`See details for ${entity.id}`} className={"shrink-0"}>
163
167
  <IconButton
164
168
  color={"inherit"}
165
- size={"medium"}
169
+ size={"small"}
166
170
  className={size !== "small" ? "self-start" : ""}
167
171
  onClick={(e) => {
168
172
  e.stopPropagation();
@@ -177,7 +181,7 @@ export function EntityPreview({
177
181
  updateUrl: true
178
182
  });
179
183
  }}>
180
- <KeyboardTabIcon size={"medium"}/>
184
+ <KeyboardTabIcon size={"small"}/>
181
185
  </IconButton>
182
186
  </Tooltip>}
183
187
 
@@ -26,7 +26,7 @@ export function ErrorView({
26
26
  tooltip
27
27
  }: ErrorViewProps): React.ReactElement {
28
28
  const component = error instanceof Error ? error.message : error;
29
- console.warn("ErrorView", error)
29
+ // console.warn("ErrorView", error)
30
30
 
31
31
  const body = (
32
32
  <div
@@ -114,6 +114,7 @@ export function DefaultHomePage({
114
114
  );
115
115
  })}
116
116
  </>;
117
+
117
118
  additionalPluginChildrenStart = <div className={"flex flex-col gap-2"}>
118
119
  {customizationController.plugins.filter(plugin => plugin.homePage?.additionalChildrenStart)
119
120
  .map((plugin, i) => {
@@ -179,7 +180,7 @@ export function DefaultHomePage({
179
180
 
180
181
  <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
181
182
  {thisGroupCollections.map((entry) => (
182
- <div key={`nav_${entry.group}_${entry.name}`} className="col-span-1">
183
+ <div key={`nav_${entry.group}_${entry.path}_${entry.name}`} className="col-span-1">
183
184
  <NavigationCardBinding
184
185
  {...entry}
185
186
  onClick={() => {
@@ -7,6 +7,7 @@ import { useUserConfigurationPersistence } from "../../hooks/useUserConfiguratio
7
7
  import { IconButton, StarIcon } from "@firecms/ui";
8
8
  import { NavigationCard } from "./NavigationCard";
9
9
  import { SmallNavigationCard } from "./SmallNavigationCard";
10
+ import React from "react";
10
11
 
11
12
  /**
12
13
  * This is the component used in the home page to render a card for each
@@ -47,6 +48,7 @@ export function NavigationCardBinding({
47
48
  ? [
48
49
  <IconButton
49
50
  key={"favourite"}
51
+ size={"small"}
50
52
  onClick={(e) => {
51
53
  e.preventDefault();
52
54
  e.stopPropagation();
@@ -61,7 +63,7 @@ export function NavigationCardBinding({
61
63
  }
62
64
  }}>
63
65
  <StarIcon
64
- size={18}
66
+ size={"small"}
65
67
  className={favourite ? "text-secondary" : "text-surface-400 dark:text-surface-500"}/>
66
68
  </IconButton>
67
69
  ]