@firecms/core 3.0.0-beta.6 → 3.0.0-beta.8

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 (185) hide show
  1. package/dist/app/AppBar.d.ts +12 -0
  2. package/dist/app/Drawer.d.ts +17 -0
  3. package/dist/app/Scaffold.d.ts +30 -0
  4. package/dist/app/index.d.ts +4 -0
  5. package/dist/app/useApp.d.ts +16 -0
  6. package/dist/components/EntityCollectionTable/EntityCollectionTable.d.ts +1 -1
  7. package/dist/components/EntityCollectionTable/EntityCollectionTableProps.d.ts +4 -2
  8. package/dist/components/EntityCollectionTable/PropertyTableCell.d.ts +1 -0
  9. package/dist/components/EntityCollectionTable/column_utils.d.ts +1 -2
  10. package/dist/components/EntityCollectionTable/fields/TableReferenceField.d.ts +2 -0
  11. package/dist/components/EntityCollectionTable/internal/EntityTableCell.d.ts +2 -2
  12. package/dist/components/EntityCollectionTable/internal/popup_field/PopupFormField.d.ts +1 -1
  13. package/dist/components/EntityPreview.d.ts +3 -2
  14. package/dist/components/ReferenceWidget.d.ts +3 -1
  15. package/dist/components/SelectableTable/filters/ReferenceFilterField.d.ts +2 -1
  16. package/dist/components/VirtualTable/VirtualTableProps.d.ts +5 -6
  17. package/dist/components/VirtualTable/types.d.ts +3 -3
  18. package/dist/components/{EntityCollectionTable/internal → common}/default_entity_actions.d.ts +1 -1
  19. package/dist/components/common/index.d.ts +1 -0
  20. package/dist/components/common/table_height.d.ts +5 -0
  21. package/dist/components/common/types.d.ts +3 -5
  22. package/dist/components/common/useDataSourceEntityCollectionTableController.d.ts +3 -0
  23. package/dist/components/index.d.ts +2 -1
  24. package/dist/{components/FireCMSAppBar.d.ts → core/DefaultAppBar.d.ts} +5 -8
  25. package/dist/core/DefaultDrawer.d.ts +19 -0
  26. package/dist/core/DrawerNavigationItem.d.ts +9 -0
  27. package/dist/core/EntityEditView.d.ts +17 -3
  28. package/dist/core/NavigationRoutes.d.ts +2 -2
  29. package/dist/core/index.d.ts +3 -4
  30. package/dist/form/PropertiesForm.d.ts +8 -0
  31. package/dist/form/components/FieldHelperText.d.ts +3 -3
  32. package/dist/form/components/StorageItemPreview.d.ts +4 -4
  33. package/dist/form/field_bindings/MapFieldBinding.d.ts +1 -1
  34. package/dist/form/field_bindings/StorageUploadFieldBinding.d.ts +2 -4
  35. package/dist/form/index.d.ts +0 -2
  36. package/dist/hooks/data/save.d.ts +1 -2
  37. package/dist/hooks/index.d.ts +1 -0
  38. package/dist/index.d.ts +1 -0
  39. package/dist/index.es.js +10199 -10140
  40. package/dist/index.es.js.map +1 -1
  41. package/dist/index.umd.js +5 -5
  42. package/dist/index.umd.js.map +1 -1
  43. package/dist/preview/PropertyPreviewProps.d.ts +5 -0
  44. package/dist/preview/components/ReferencePreview.d.ts +2 -1
  45. package/dist/preview/components/StorageThumbnail.d.ts +2 -1
  46. package/dist/preview/components/UrlComponentPreview.d.ts +2 -1
  47. package/dist/types/auth.d.ts +1 -1
  48. package/dist/types/collections.d.ts +22 -1
  49. package/dist/types/datasource.d.ts +18 -8
  50. package/dist/types/entity_actions.d.ts +14 -0
  51. package/dist/types/fields.d.ts +31 -30
  52. package/dist/types/navigation.d.ts +2 -2
  53. package/dist/types/plugins.d.ts +11 -3
  54. package/dist/types/properties.d.ts +15 -2
  55. package/dist/util/icon_synonyms.d.ts +1 -97
  56. package/dist/util/icons.d.ts +2 -2
  57. package/dist/util/objects.d.ts +1 -1
  58. package/dist/util/resolutions.d.ts +8 -8
  59. package/dist/util/storage.d.ts +23 -2
  60. package/dist/util/useStorageUploadController.d.ts +1 -1
  61. package/package.json +130 -122
  62. package/src/app/AppBar.tsx +18 -0
  63. package/src/app/Drawer.tsx +25 -0
  64. package/src/app/Scaffold.tsx +249 -0
  65. package/src/app/index.ts +4 -0
  66. package/src/app/useApp.tsx +32 -0
  67. package/src/components/EntityCollectionTable/EntityCollectionRowActions.tsx +8 -10
  68. package/src/components/EntityCollectionTable/EntityCollectionTable.tsx +9 -7
  69. package/src/components/EntityCollectionTable/EntityCollectionTableProps.tsx +9 -5
  70. package/src/components/EntityCollectionTable/PropertyTableCell.tsx +22 -15
  71. package/src/components/EntityCollectionTable/column_utils.tsx +3 -3
  72. package/src/components/EntityCollectionTable/fields/TableReferenceField.tsx +9 -1
  73. package/src/components/EntityCollectionTable/fields/TableStorageUpload.tsx +2 -2
  74. package/src/components/EntityCollectionTable/internal/CollectionTableToolbar.tsx +2 -2
  75. package/src/components/EntityCollectionTable/internal/EntityTableCell.tsx +5 -6
  76. package/src/components/EntityCollectionTable/internal/popup_field/PopupFormField.tsx +4 -5
  77. package/src/components/EntityCollectionView/EntityCollectionView.tsx +26 -24
  78. package/src/components/EntityPreview.tsx +9 -7
  79. package/src/components/EntityView.tsx +4 -4
  80. package/src/components/HomePage/NavigationCard.tsx +2 -2
  81. package/src/components/HomePage/SmallNavigationCard.tsx +5 -5
  82. package/src/components/PropertyIdCopyTooltipContent.tsx +2 -3
  83. package/src/components/ReferenceTable/ReferenceSelectionTable.tsx +1 -0
  84. package/src/components/ReferenceWidget.tsx +21 -11
  85. package/src/components/SearchIconsView.tsx +5 -5
  86. package/src/components/SelectableTable/SelectableTable.tsx +4 -2
  87. package/src/components/SelectableTable/filters/ReferenceFilterField.tsx +4 -1
  88. package/src/components/VirtualTable/VirtualTable.tsx +13 -12
  89. package/src/components/VirtualTable/VirtualTableHeader.tsx +4 -4
  90. package/src/components/VirtualTable/VirtualTableHeaderRow.tsx +2 -2
  91. package/src/components/VirtualTable/VirtualTableProps.tsx +6 -6
  92. package/src/components/VirtualTable/VirtualTableRow.tsx +4 -5
  93. package/src/components/VirtualTable/types.tsx +2 -3
  94. package/src/components/{EntityCollectionTable/internal → common}/default_entity_actions.tsx +2 -2
  95. package/src/components/common/index.ts +1 -0
  96. package/src/components/{VirtualTable/common.tsx → common/table_height.tsx} +5 -2
  97. package/src/components/common/types.tsx +3 -5
  98. package/src/components/common/useColumnsIds.tsx +10 -2
  99. package/src/components/common/useDataSourceEntityCollectionTableController.tsx +11 -0
  100. package/src/components/common/useTableSearchHelper.ts +52 -12
  101. package/src/components/index.tsx +2 -1
  102. package/src/contexts/DialogsProvider.tsx +2 -2
  103. package/src/{components/FireCMSAppBar.tsx → core/DefaultAppBar.tsx} +51 -36
  104. package/src/core/DefaultDrawer.tsx +177 -0
  105. package/src/core/DrawerNavigationItem.tsx +62 -0
  106. package/src/core/EntityEditView.tsx +673 -134
  107. package/src/core/EntitySidePanel.tsx +1 -2
  108. package/src/core/FireCMS.tsx +36 -40
  109. package/src/core/NavigationRoutes.tsx +6 -7
  110. package/src/core/field_configs.tsx +1 -1
  111. package/src/core/index.tsx +3 -4
  112. package/src/form/PropertiesForm.tsx +81 -0
  113. package/src/form/PropertyFieldBinding.tsx +29 -7
  114. package/src/form/components/FieldHelperText.tsx +3 -3
  115. package/src/form/components/StorageItemPreview.tsx +20 -11
  116. package/src/form/components/StorageUploadProgress.tsx +3 -3
  117. package/src/form/field_bindings/ArrayCustomShapedFieldBinding.tsx +8 -5
  118. package/src/form/field_bindings/ArrayOfReferencesFieldBinding.tsx +8 -5
  119. package/src/form/field_bindings/BlockFieldBinding.tsx +2 -2
  120. package/src/form/field_bindings/KeyValueFieldBinding.tsx +44 -39
  121. package/src/form/field_bindings/MapFieldBinding.tsx +11 -3
  122. package/src/form/field_bindings/MarkdownFieldBinding.tsx +2 -2
  123. package/src/form/field_bindings/ReadOnlyFieldBinding.tsx +2 -9
  124. package/src/form/field_bindings/ReferenceFieldBinding.tsx +15 -13
  125. package/src/form/field_bindings/RepeatFieldBinding.tsx +10 -7
  126. package/src/form/field_bindings/SelectFieldBinding.tsx +3 -3
  127. package/src/form/field_bindings/StorageUploadFieldBinding.tsx +10 -39
  128. package/src/form/field_bindings/SwitchFieldBinding.tsx +1 -1
  129. package/src/form/index.tsx +4 -4
  130. package/src/form/validation.ts +1 -17
  131. package/src/hooks/data/save.ts +2 -1
  132. package/src/hooks/index.tsx +1 -0
  133. package/src/hooks/useBuildLocalConfigurationPersistence.tsx +2 -3
  134. package/src/hooks/useBuildNavigationController.tsx +1 -2
  135. package/src/hooks/useResolvedNavigationFrom.tsx +1 -1
  136. package/src/hooks/useValidateAuthenticator.tsx +15 -15
  137. package/src/index.ts +1 -0
  138. package/src/internal/useBuildDataSource.ts +12 -0
  139. package/src/internal/useBuildSideEntityController.tsx +72 -11
  140. package/src/preview/PropertyPreview.tsx +7 -4
  141. package/src/preview/PropertyPreviewProps.tsx +6 -0
  142. package/src/preview/components/BooleanPreview.tsx +2 -2
  143. package/src/preview/components/EnumValuesChip.tsx +1 -1
  144. package/src/preview/components/ImagePreview.tsx +21 -33
  145. package/src/preview/components/ReferencePreview.tsx +22 -22
  146. package/src/preview/components/StorageThumbnail.tsx +5 -1
  147. package/src/preview/components/UrlComponentPreview.tsx +44 -11
  148. package/src/preview/property_previews/ArrayOfMapsPreview.tsx +0 -1
  149. package/src/preview/property_previews/ArrayOfReferencesPreview.tsx +2 -1
  150. package/src/preview/property_previews/ArrayOfStorageComponentsPreview.tsx +0 -1
  151. package/src/preview/property_previews/ArrayOfStringsPreview.tsx +0 -1
  152. package/src/preview/property_previews/ArrayOneOfPreview.tsx +2 -3
  153. package/src/preview/property_previews/ArrayPropertyPreview.tsx +2 -3
  154. package/src/preview/property_previews/MapPropertyPreview.tsx +5 -5
  155. package/src/preview/property_previews/StringPropertyPreview.tsx +2 -2
  156. package/src/types/auth.tsx +1 -1
  157. package/src/types/collections.ts +28 -2
  158. package/src/types/customization_controller.tsx +0 -1
  159. package/src/types/datasource.ts +20 -16
  160. package/src/types/entity_actions.tsx +16 -3
  161. package/src/types/fields.tsx +33 -33
  162. package/src/types/navigation.ts +1 -2
  163. package/src/types/plugins.tsx +12 -3
  164. package/src/types/properties.ts +17 -2
  165. package/src/types/storage.ts +1 -1
  166. package/src/util/entities.ts +4 -3
  167. package/src/util/enums.ts +1 -1
  168. package/src/util/icon_list.ts +2 -2
  169. package/src/util/icon_synonyms.ts +3 -99
  170. package/src/util/objects.ts +25 -28
  171. package/src/util/permissions.ts +1 -0
  172. package/src/util/resolutions.ts +32 -31
  173. package/src/util/storage.ts +75 -21
  174. package/src/util/useStorageUploadController.tsx +21 -3
  175. package/dist/components/VirtualTable/common.d.ts +0 -2
  176. package/dist/core/Drawer.d.ts +0 -23
  177. package/dist/core/Scaffold.d.ts +0 -55
  178. package/dist/core/SideEntityView.d.ts +0 -7
  179. package/dist/form/EntityForm.d.ts +0 -77
  180. package/dist/internal/useBuildCustomizationController.d.ts +0 -2
  181. package/src/core/Drawer.tsx +0 -191
  182. package/src/core/Scaffold.tsx +0 -281
  183. package/src/core/SideEntityView.tsx +0 -38
  184. package/src/form/EntityForm.tsx +0 -728
  185. package/src/internal/useBuildCustomizationController.tsx +0 -5
@@ -17,7 +17,6 @@ import { resolveCollection } from "../../util";
17
17
  export type SaveEntityWithCallbacksProps<M extends Record<string, any>> =
18
18
  SaveEntityProps<M> &
19
19
  {
20
- callbacks?: EntityCallbacks<M>;
21
20
  onSaveSuccess?: (updatedEntity: Entity<M>) => void,
22
21
  onSaveFailure?: (e: Error) => void,
23
22
  onPreSaveHookError?: (e: Error) => void,
@@ -109,6 +108,7 @@ export async function saveEntityWithCallbacks<M extends Record<string, any>, Use
109
108
  updatedValues = values;
110
109
  }
111
110
 
111
+ console.log("Saving entity", entityId, updatedValues);
112
112
  return dataSource.saveEntity({
113
113
  collection,
114
114
  path: resolvedPath,
@@ -117,6 +117,7 @@ export async function saveEntityWithCallbacks<M extends Record<string, any>, Use
117
117
  previousValues,
118
118
  status
119
119
  }).then((entity) => {
120
+ console.log("Entity saved");
120
121
  try {
121
122
  if (callbacks?.onSaveSuccess) {
122
123
  const resolvedCollection = resolveCollection<M>({
@@ -10,6 +10,7 @@ export * from "./useResolvedNavigationFrom";
10
10
 
11
11
  export * from "./useStorageSource";
12
12
  export * from "./useAuthController";
13
+ export * from "./useDialogsController";
13
14
  export * from "./useSideDialogsController";
14
15
  export * from "./useSideEntityController";
15
16
  export * from "./useFireCMSContext";
@@ -22,10 +22,9 @@ export function useBuildLocalConfigurationPersistence(): UserConfigurationPersis
22
22
  const onCollectionModified = useCallback(<M extends Record<string, any>>(path: string, data: PartialEntityCollection<M>) => {
23
23
  const storageKey = `collection_config::${stripCollectionPath(path)}`;
24
24
  localStorage.setItem(storageKey, JSON.stringify(data));
25
- const currentCache = configCache.current;
26
- const cachedConfig = currentCache[storageKey];
25
+ const cachedConfig = configCache.current[storageKey];
27
26
  const newConfig = mergeDeep(cachedConfig ?? getCollectionFromStorage(path), data);
28
- configCache.current = mergeDeep(currentCache, newConfig);
27
+ configCache.current[storageKey] = mergeDeep(configCache.current[storageKey], newConfig);
29
28
  }, [getCollectionFromStorage]);
30
29
 
31
30
  const [recentlyVisitedPaths, _setRecentlyVisitedPaths] = useState<string[]>([]);
@@ -241,7 +241,6 @@ export function useBuildNavigationController<EC extends EntityCollection, UserTy
241
241
 
242
242
  const getCollection = useCallback((
243
243
  idOrPath: string,
244
- entityId?: string,
245
244
  includeUserOverride = false
246
245
  ): EC | undefined => {
247
246
  const collections = collectionsRef.current;
@@ -251,7 +250,7 @@ export function useBuildNavigationController<EC extends EntityCollection, UserTy
251
250
  const baseCollection = getCollectionByPathOrId(removeInitialAndTrailingSlashes(idOrPath), collections);
252
251
 
253
252
  const userOverride = includeUserOverride ? userConfigPersistence?.getCollectionConfig(idOrPath) : undefined;
254
- const overriddenCollection = baseCollection ? mergeDeep(baseCollection, userOverride) : undefined;
253
+ const overriddenCollection = baseCollection ? mergeDeep(baseCollection, userOverride ?? {}) : undefined;
255
254
 
256
255
  let result: Partial<EntityCollection> | undefined = overriddenCollection;
257
256
 
@@ -80,7 +80,7 @@ export function resolveNavigationFrom<M extends Record<string, any>, UserType ex
80
80
  if (entry.type === "collection") {
81
81
  return Promise.resolve(entry);
82
82
  } else if (entry.type === "entity") {
83
- const collection = navigation.getCollection(entry.path, entry.entityId);
83
+ const collection = navigation.getCollection(entry.path);
84
84
  if (!collection) {
85
85
  throw Error(`No collection defined in the navigation for the entity with path ${entry.path}`);
86
86
  }
@@ -11,20 +11,21 @@ import { AuthController, Authenticator, DataSourceDelegate, StorageSource, User
11
11
  * @param storageSource
12
12
  * @param dataSourceDelegate
13
13
  */
14
- export function useValidateAuthenticator<UserType extends User = User, Controller extends AuthController<UserType> = AuthController<UserType>>({
15
- disabled,
16
- authController,
17
- authenticator,
18
- storageSource,
19
- dataSourceDelegate
20
- }:
21
- {
22
- disabled?: boolean,
23
- authController: Controller,
24
- authenticator?: boolean | Authenticator<UserType, Controller>,
25
- dataSourceDelegate: DataSourceDelegate;
26
- storageSource: StorageSource;
27
- }): {
14
+ export function useValidateAuthenticator<UserType extends User = User, Controller extends AuthController<UserType> = AuthController<UserType>>
15
+ ({
16
+ disabled,
17
+ authController,
18
+ authenticator,
19
+ storageSource,
20
+ dataSourceDelegate
21
+ }:
22
+ {
23
+ disabled?: boolean,
24
+ authController: Controller,
25
+ authenticator?: boolean | Authenticator<UserType, Controller>,
26
+ dataSourceDelegate: DataSourceDelegate;
27
+ storageSource: StorageSource;
28
+ }): {
28
29
  canAccessMainView: boolean,
29
30
  authLoading: boolean,
30
31
  notAllowedError: any,
@@ -70,7 +71,6 @@ export function useValidateAuthenticator<UserType extends User = User, Controlle
70
71
  }
71
72
 
72
73
  const delegateUser = authController.user;
73
- console.debug("Checking authentication for user", delegateUser);
74
74
 
75
75
  if (authenticator instanceof Function && delegateUser && !equal(checkedUserRef.current?.uid, delegateUser.uid)) {
76
76
  setAuthLoading(true);
package/src/index.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export * from "./core";
2
+ export * from "./app";
2
3
  export * from "./types";
3
4
  export * from "./form";
4
5
  export * from "./preview";
@@ -9,6 +9,7 @@ import {
9
9
  FetchCollectionProps,
10
10
  FetchEntityProps,
11
11
  FilterValues,
12
+ FireCMSContext,
12
13
  ListenCollectionProps,
13
14
  ListenEntityProps,
14
15
  NavigationController,
@@ -313,6 +314,17 @@ export function useBuildDataSource({
313
314
  )
314
315
  }, [delegate.isFilterCombinationValid]),
315
316
 
317
+ initTextSearch: useCallback(async (props: {
318
+ context: FireCMSContext,
319
+ path: string,
320
+ collection: EntityCollection,
321
+ parentCollectionIds?: string[]
322
+ }): Promise<boolean> => {
323
+ if (!delegate.initTextSearch)
324
+ return false;
325
+ return delegate.initTextSearch(props)
326
+ }, [delegate.initTextSearch]),
327
+
316
328
  };
317
329
 
318
330
  }
@@ -2,14 +2,15 @@ import { useCallback, useEffect, useRef } from "react";
2
2
  import {
3
3
  EntityCollection,
4
4
  EntitySidePanelProps,
5
- NavigationController,
5
+ NavigationController, PropertyConfig,
6
+ ResolvedProperty,
6
7
  SideDialogPanelProps,
7
8
  SideDialogsController,
8
9
  SideEntityController
9
10
  } from "../types";
10
11
  import { getNavigationEntriesFromPathInternal, NavigationViewInternal } from "../util/navigation_from_path";
11
12
  import { useLocation } from "react-router-dom";
12
- import { removeInitialAndTrailingSlashes, resolveDefaultSelectedView } from "../util";
13
+ import { removeInitialAndTrailingSlashes, resolveCollection, resolveDefaultSelectedView } from "../util";
13
14
  import { ADDITIONAL_TAB_WIDTH, CONTAINER_FULL_WIDTH, FORM_CONTAINER_WIDTH } from "./common";
14
15
  import { useLargeLayout } from "../hooks";
15
16
  import { EntitySidePanel } from "../core/EntitySidePanel";
@@ -19,8 +20,67 @@ const NEW_URL_HASH = "new";
19
20
  export function getEntityViewWidth(props: EntitySidePanelProps<any>, small: boolean): string {
20
21
  if (small) return CONTAINER_FULL_WIDTH;
21
22
  const mainViewSelected = !props.selectedSubPath;
22
- const resolvedWidth: string | undefined = typeof props.width === "number" ? `${props.width}px` : props.width;
23
- return !mainViewSelected ? `calc(${ADDITIONAL_TAB_WIDTH} + ${resolvedWidth ?? FORM_CONTAINER_WIDTH})` : resolvedWidth ?? FORM_CONTAINER_WIDTH
23
+ let resolvedWidth: string | undefined;
24
+ if (props.width) {
25
+ resolvedWidth = typeof props.width === "number" ? `${props.width}px` : props.width;
26
+ } else if (props.collection?.sideDialogWidth) {
27
+ resolvedWidth = typeof props.collection.sideDialogWidth === "number" ? `${props.collection.sideDialogWidth}px` : props.collection.sideDialogWidth;
28
+ }
29
+
30
+ if (!mainViewSelected) {
31
+ return `calc(${ADDITIONAL_TAB_WIDTH} + ${resolvedWidth ?? FORM_CONTAINER_WIDTH})`
32
+ } else {
33
+ if (resolvedWidth) {
34
+ return resolvedWidth
35
+ } else if (!props.collection) {
36
+ return FORM_CONTAINER_WIDTH;
37
+ } else {
38
+ return calculateCollectionDesiredWidth(props.collection);
39
+ }
40
+ }
41
+ }
42
+
43
+ const collectionViewWidthCache: { [key: string]: string } = {};
44
+
45
+ function calculateCollectionDesiredWidth(collection: EntityCollection<any>): string {
46
+ if (collectionViewWidthCache[collection.id]) {
47
+ return collectionViewWidthCache[collection.id];
48
+ }
49
+ const resolvedCollection = resolveCollection({
50
+ collection,
51
+ path: "__ignored",
52
+ ignoreMissingFields: true
53
+ });
54
+
55
+ let result = FORM_CONTAINER_WIDTH
56
+ if (resolvedCollection?.properties) {
57
+ const values = Object.values(resolvedCollection.properties).map((p: ResolvedProperty) => getNestedPropertiesDepth(p));
58
+ const maxDepth = Math.max(...values);
59
+ if (maxDepth < 3) {
60
+ result = FORM_CONTAINER_WIDTH;
61
+ } else {
62
+ result = 768 + 32 * (maxDepth - 2) + "px";
63
+ }
64
+ }
65
+ collectionViewWidthCache[collection.id] = result;
66
+ return result;
67
+ }
68
+
69
+ function getNestedPropertiesDepth(property: ResolvedProperty, accumulator: number = 0): number {
70
+ if (property.dataType === "map" && property.properties) {
71
+ const values = Object.values(property.properties).flatMap((property) => getNestedPropertiesDepth(property, accumulator + 1));
72
+ return Math.max(...values);
73
+ } else if (property.dataType === "array" && property.oneOf) {
74
+ return accumulator + 3;
75
+ } else if (property.dataType === "array" && property.of) {
76
+ if (Array.isArray(property.of)) {
77
+ return Math.max(...property.of.map((p) => getNestedPropertiesDepth(p, accumulator + 1)));
78
+ } else {
79
+ return getNestedPropertiesDepth(property.of, accumulator + 1);
80
+ }
81
+ } else {
82
+ return accumulator + 1;
83
+ }
24
84
  }
25
85
 
26
86
  export const useBuildSideEntityController = (navigation: NavigationController,
@@ -40,12 +100,12 @@ export const useBuildSideEntityController = (navigation: NavigationController,
40
100
  const entityOrCollectionPath = navigation.urlPathToDataPath(location.pathname);
41
101
  const panelsFromUrl = buildSidePanelsFromUrl(entityOrCollectionPath, navigation.collections ?? [], newFlag);
42
102
  for (let i = 0; i < panelsFromUrl.length; i++) {
43
- const panel = panelsFromUrl[i];
103
+ const props = panelsFromUrl[i];
44
104
  setTimeout(() => {
45
105
  if (i === 0)
46
- sideDialogsController.replace(propsToSidePanel(panel, navigation.buildUrlCollectionPath, navigation.resolveAliasesFrom, smallLayout));
106
+ sideDialogsController.replace(propsToSidePanel(props, navigation.buildUrlCollectionPath, navigation.resolveAliasesFrom, smallLayout));
47
107
  else
48
- sideDialogsController.open(propsToSidePanel(panel, navigation.buildUrlCollectionPath, navigation.resolveAliasesFrom, smallLayout))
108
+ sideDialogsController.open(propsToSidePanel(props, navigation.buildUrlCollectionPath, navigation.resolveAliasesFrom, smallLayout))
49
109
  }, 1);
50
110
  }
51
111
  } else {
@@ -119,7 +179,8 @@ export function buildSidePanelsFromUrl(path: string, collections: EntityCollecti
119
179
  sidePanels.push({
120
180
  path: navigationEntry.path,
121
181
  entityId: navigationEntry.entityId,
122
- copy: false
182
+ copy: false,
183
+ width: navigationEntry.parentCollection?.sideDialogWidth
123
184
  }
124
185
  );
125
186
  } else if (navigationEntry.type === "custom_view") {
@@ -163,16 +224,16 @@ const propsToSidePanel = (props: EntitySidePanelProps<any>,
163
224
 
164
225
  const resolvedPanelProps: EntitySidePanelProps<any> = {
165
226
  ...props,
166
- path: resolvedPath
227
+ path: resolvedPath,
167
228
  };
168
229
 
169
- return ({
230
+ return {
170
231
  key: `${props.path}/${props.entityId}`,
171
232
  component: <EntitySidePanel {...resolvedPanelProps}/>,
172
233
  urlPath: newPath,
173
234
  parentUrlPath: buildUrlCollectionPath(collectionPath),
174
235
  width: getEntityViewWidth(props, smallLayout),
175
236
  onClose: props.onClose
176
- });
237
+ };
177
238
  }
178
239
  ;
@@ -47,13 +47,12 @@ export const PropertyPreview = React.memo(function PropertyPreview<T extends CMS
47
47
  size,
48
48
  height,
49
49
  width,
50
- // entity
50
+ interactive
51
51
  } = props;
52
52
 
53
53
  const property = resolveProperty({
54
54
  propertyKey,
55
55
  propertyOrBuilder: inputProperty,
56
- propertyValue: value,
57
56
  fields: customizationController.propertyConfigs
58
57
  });
59
58
 
@@ -85,12 +84,15 @@ export const PropertyPreview = React.memo(function PropertyPreview<T extends CMS
85
84
  content =
86
85
  <UrlComponentPreview size={props.size}
87
86
  url={value}
87
+ interactive={interactive}
88
88
  previewType={stringProperty.url}/>;
89
89
  } else if (stringProperty.storage) {
90
+ const filePath = stringProperty.storage.previewUrl ? stringProperty.storage.previewUrl(value) : value;
90
91
  content = <StorageThumbnail
92
+ interactive={interactive}
91
93
  storeUrl={property.storage?.storeUrl ?? false}
92
94
  size={props.size}
93
- storagePathOrDownloadUrl={value}/>;
95
+ storagePathOrDownloadUrl={filePath}/>;
94
96
  } else if (stringProperty.markdown) {
95
97
  content = <Markdown source={value} size={"small"}/>;
96
98
  } else {
@@ -172,8 +174,9 @@ export const PropertyPreview = React.memo(function PropertyPreview<T extends CMS
172
174
  content = <ReferencePreview
173
175
  disabled={!property.path}
174
176
  previewProperties={property.previewProperties}
177
+ includeId={property.includeId}
178
+ includeEntityLink={property.includeEntityLink}
175
179
  size={props.size}
176
- // onClick={props.onClick}
177
180
  reference={value as EntityReference}
178
181
  />;
179
182
  } else {
@@ -46,4 +46,10 @@ export interface PropertyPreviewProps<T extends CMSType = any, CustomProps = any
46
46
  */
47
47
  customProps?: CustomProps;
48
48
 
49
+ /**
50
+ * If the preview should be interactive or not.
51
+ * This applies only to videos.
52
+ */
53
+ interactive?: boolean;
54
+
49
55
  }
@@ -1,5 +1,5 @@
1
1
  import React from "react";
2
- import { Checkbox, cn } from "@firecms/ui";
2
+ import { Checkbox, cls } from "@firecms/ui";
3
3
  import { PreviewSize } from "../PropertyPreviewProps";
4
4
  import { Property } from "../../types";
5
5
 
@@ -21,6 +21,6 @@ export function BooleanPreview({
21
21
  size={size}
22
22
  color={"secondary"}/>
23
23
  {property.name && <span
24
- className={cn("text-text-secondary dark:text-text-secondary-dark", size === "tiny" ? "text-sm" : "")}>{property.name}</span>}
24
+ className={cls("text-text-secondary dark:text-text-secondary-dark", size === "tiny" ? "text-sm" : "")}>{property.name}</span>}
25
25
  </div>;
26
26
  }
@@ -1,7 +1,7 @@
1
1
  import React from "react";
2
+ import { Chip } from "@firecms/ui";
2
3
  import { EnumValues } from "../../types";
3
4
  import { buildEnumLabel, enumToObjectEntries, getColorScheme, getLabelOrConfigFrom } from "../../util/enums";
4
- import { Chip } from "@firecms/ui";
5
5
 
6
6
  export interface EnumValuesChipProps {
7
7
  enumValues?: EnumValues;
@@ -1,4 +1,4 @@
1
- import React, { CSSProperties, useMemo, useState } from "react";
1
+ import React, { CSSProperties, useMemo } from "react";
2
2
 
3
3
  import { getThumbnailMeasure } from "../util";
4
4
  import { PreviewSize } from "../PropertyPreviewProps";
@@ -20,8 +20,6 @@ export function ImagePreview({
20
20
  url
21
21
  }: ImagePreviewProps) {
22
22
 
23
- const [onHover, setOnHover] = useState(false);
24
-
25
23
  const imageSize = useMemo(() => getThumbnailMeasure(size), [size]);
26
24
 
27
25
  if (size === "tiny") {
@@ -47,60 +45,50 @@ export function ImagePreview({
47
45
 
48
46
  return (
49
47
  <div
50
- className="relative flex items-center justify-center max-w-full max-h-full"
48
+ className="relative flex items-center justify-center max-w-full max-h-full group"
51
49
  style={{
52
50
  width: imageSize,
53
51
  height: imageSize
54
52
  }}
55
- key={"image_preview_" + url}
56
- onMouseEnter={() => setOnHover(true)}
57
- onMouseMove={() => setOnHover(true)}
58
- onMouseLeave={() => setOnHover(false)}>
53
+ key={"image_preview_" + url}>
59
54
 
60
55
  <img src={url}
61
56
  className={"rounded-md"}
62
57
  style={imageStyle}/>
63
58
 
64
- {onHover && <>
65
59
 
66
- {navigator && <Tooltip title="Copy url to clipboard">
67
- <div
68
- className="rounded-full absolute bottom-[-4px] right-8">
69
- <IconButton
70
- variant={"filled"}
71
- size={"small"}
72
- onClick={(e) => {
73
- e.stopPropagation();
74
- e.preventDefault();
75
- return navigator.clipboard.writeText(url);
76
- }}>
77
- <ContentCopyIcon className={"text-gray-500"}
78
- size={"small"}/>
79
- </IconButton>
80
- </div>
60
+ <div className={"flex flex-row gap-2 absolute bottom-[-4px] right-[-4px] invisible group-hover:visible"}>
61
+ {navigator && <Tooltip title="Copy url to clipboard" side={"bottom"}>
62
+ <IconButton
63
+ variant={"filled"}
64
+ size={"small"}
65
+ onClick={(e) => {
66
+ e.stopPropagation();
67
+ e.preventDefault();
68
+ return navigator.clipboard.writeText(url);
69
+ }}>
70
+ <ContentCopyIcon className={"text-gray-700 dark:text-gray-300"}
71
+ size={"small"}/>
72
+ </IconButton>
81
73
  </Tooltip>}
82
74
 
83
- <Tooltip title="Open image in new tab">
75
+ <Tooltip title="Open image in new tab" side={"bottom"}>
84
76
  <IconButton
77
+ className="invisible group-hover:visible"
85
78
  variant={"filled"}
86
79
  component={"a" as React.ElementType}
87
- style={{
88
- position: "absolute",
89
- bottom: -4,
90
- right: -4
91
- }}
92
80
  href={url}
93
81
  rel="noopener noreferrer"
94
82
  target="_blank"
95
83
  size={"small"}
96
84
  onClick={(e: any) => e.stopPropagation()}
97
85
  >
98
- <OpenInNewIcon className={"text-gray-500"}
86
+ <OpenInNewIcon className={"text-gray-700 dark:text-gray-300"}
99
87
  size={"small"}/>
100
88
  </IconButton>
101
89
  </Tooltip>
102
- </>
103
- }
90
+ </div>
91
+
104
92
  </div>
105
93
  );
106
94
  }
@@ -1,16 +1,10 @@
1
1
  import * as React from "react";
2
2
 
3
3
  import { Entity, EntityCollection, EntityReference } from "../../types";
4
- import {
5
- useCustomizationController,
6
- useEntityFetch,
7
- useNavigationController,
8
- useSideEntityController
9
- } from "../../hooks";
4
+ import { useCustomizationController, useEntityFetch, useNavigationController } from "../../hooks";
10
5
  import { PreviewSize } from "../PropertyPreviewProps";
11
- import { IconButton, KeyboardTabIcon, Skeleton, Tooltip } from "@firecms/ui";
6
+ import { Skeleton } from "@firecms/ui";
12
7
  import { ErrorView } from "../../components";
13
- import { useAnalyticsController } from "../../hooks/useAnalyticsController";
14
8
  import { EntityPreview, EntityPreviewContainer } from "../../components/EntityPreview";
15
9
 
16
10
  export type ReferencePreviewProps = {
@@ -20,7 +14,8 @@ export type ReferencePreviewProps = {
20
14
  previewProperties?: string[];
21
15
  onClick?: (e: React.SyntheticEvent) => void;
22
16
  hover?: boolean;
23
- allowEntityNavigation?: boolean;
17
+ includeEntityLink?: boolean;
18
+ includeId?: boolean;
24
19
  };
25
20
 
26
21
  /**
@@ -46,19 +41,21 @@ function areEqual(prevProps: ReferencePreviewProps, nextProps: ReferencePreviewP
46
41
  prevProps.hover === nextProps.hover &&
47
42
  prevProps.reference?.id === nextProps.reference?.id &&
48
43
  prevProps.reference?.path === nextProps.reference?.path &&
49
- prevProps.allowEntityNavigation === nextProps.allowEntityNavigation
44
+ prevProps.includeEntityLink === nextProps.includeEntityLink &&
45
+ prevProps.onClick === nextProps.onClick
50
46
  ;
51
47
  }
52
48
 
53
- function ReferencePreviewInternal<M extends Record<string, any>>({
54
- disabled,
55
- reference,
56
- previewProperties,
57
- size,
58
- hover,
59
- onClick,
60
- allowEntityNavigation = true
61
- }: ReferencePreviewProps) {
49
+ function ReferencePreviewInternal({
50
+ disabled,
51
+ reference,
52
+ previewProperties,
53
+ size,
54
+ hover,
55
+ onClick,
56
+ includeEntityLink = true,
57
+ includeId = true
58
+ }: ReferencePreviewProps) {
62
59
 
63
60
  const customizationController = useCustomizationController();
64
61
 
@@ -79,7 +76,8 @@ function ReferencePreviewInternal<M extends Record<string, any>>({
79
76
  previewProperties={previewProperties}
80
77
  size={size}
81
78
  disabled={disabled}
82
- allowEntityNavigation={allowEntityNavigation}
79
+ includeEntityLink={includeEntityLink}
80
+ includeId={includeId}
83
81
  onClick={onClick}
84
82
  hover={hover}/>
85
83
  }
@@ -90,7 +88,8 @@ function ReferencePreviewExisting<M extends Record<string, any> = any>({
90
88
  previewProperties,
91
89
  size,
92
90
  disabled,
93
- allowEntityNavigation,
91
+ includeEntityLink,
92
+ includeId,
94
93
  onClick,
95
94
  hover
96
95
  }: ReferencePreviewProps & {
@@ -158,7 +157,8 @@ function ReferencePreviewExisting<M extends Record<string, any> = any>({
158
157
  entity={usedEntity}
159
158
  collection={collection}
160
159
  onClick={onClick}
161
- includeEntityNavigation={allowEntityNavigation}
160
+ includeEntityLink={includeEntityLink}
161
+ includeId={includeId}
162
162
  hover={hover}/>;
163
163
 
164
164
  }
@@ -11,6 +11,7 @@ type StorageThumbnailProps = {
11
11
  storagePathOrDownloadUrl: string;
12
12
  storeUrl: boolean;
13
13
  size: PreviewSize;
14
+ interactive?: boolean;
14
15
  };
15
16
 
16
17
  /**
@@ -21,13 +22,15 @@ export const StorageThumbnail = React.memo<StorageThumbnailProps>(StorageThumbna
21
22
  function areEqual(prevProps: StorageThumbnailProps, nextProps: StorageThumbnailProps) {
22
23
  return prevProps.size === nextProps.size &&
23
24
  prevProps.storagePathOrDownloadUrl === nextProps.storagePathOrDownloadUrl &&
24
- prevProps.storeUrl === nextProps.storeUrl;
25
+ prevProps.storeUrl === nextProps.storeUrl&&
26
+ prevProps.interactive === nextProps.interactive;
25
27
  }
26
28
 
27
29
  const URL_CACHE: Record<string, DownloadConfig> = {};
28
30
 
29
31
  export function StorageThumbnailInternal({
30
32
  storeUrl,
33
+ interactive,
31
34
  storagePathOrDownloadUrl,
32
35
  size
33
36
  }: StorageThumbnailProps) {
@@ -68,6 +71,7 @@ export function StorageThumbnailInternal({
68
71
  return downloadConfig?.url
69
72
  ? <UrlComponentPreview previewType={previewType}
70
73
  url={downloadConfig.url}
74
+ interactive={interactive}
71
75
  size={size}
72
76
  hint={storagePathOrDownloadUrl}/>
73
77
  : renderSkeletonImageThumbnail(size);