@firecms/core 3.0.0-beta.11 → 3.0.0-beta.12

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 (173) hide show
  1. package/dist/components/ArrayContainer.d.ts +7 -3
  2. package/dist/components/EntityCollectionTable/EntityCollectionRowActions.d.ts +2 -1
  3. package/dist/components/EntityCollectionTable/EntityCollectionTable.d.ts +2 -2
  4. package/dist/components/EntityCollectionTable/EntityCollectionTableProps.d.ts +15 -1
  5. package/dist/components/EntityCollectionTable/index.d.ts +1 -1
  6. package/dist/components/EntityCollectionView/EntityCollectionView.d.ts +4 -0
  7. package/dist/components/PropertyIdCopyTooltip.d.ts +1 -1
  8. package/dist/components/SelectableTable/SelectableTable.d.ts +12 -2
  9. package/dist/components/SelectableTable/filters/ReferenceFilterField.d.ts +1 -1
  10. package/dist/components/UnsavedChangesDialog.d.ts +8 -0
  11. package/dist/components/VirtualTable/VirtualTableProps.d.ts +13 -0
  12. package/dist/components/common/default_entity_actions.d.ts +0 -2
  13. package/dist/components/common/index.d.ts +1 -1
  14. package/dist/components/common/useColumnsIds.d.ts +1 -0
  15. package/dist/components/common/{useDataSourceEntityCollectionTableController.d.ts → useDataSourceTableController.d.ts} +10 -2
  16. package/dist/components/common/useDebouncedCallback.d.ts +1 -0
  17. package/dist/components/common/useScrollRestoration.d.ts +14 -0
  18. package/dist/contexts/BreacrumbsContext.d.ts +8 -0
  19. package/dist/core/EntityEditView.d.ts +29 -21
  20. package/dist/core/EntityEditViewFormActions.d.ts +2 -0
  21. package/dist/core/FireCMSRouter.d.ts +4 -0
  22. package/dist/core/NavigationRoutes.d.ts +0 -1
  23. package/dist/core/SideDialogs.d.ts +4 -2
  24. package/dist/core/index.d.ts +2 -1
  25. package/dist/form/EntityForm.d.ts +45 -0
  26. package/dist/form/EntityFormActions.d.ts +17 -0
  27. package/dist/form/PropertyFieldBinding.d.ts +1 -1
  28. package/dist/form/components/FormEntry.d.ts +6 -0
  29. package/dist/form/components/FormLayout.d.ts +5 -0
  30. package/dist/form/components/index.d.ts +2 -0
  31. package/dist/form/field_bindings/ArrayCustomShapedFieldBinding.d.ts +1 -1
  32. package/dist/form/field_bindings/ArrayOfReferencesFieldBinding.d.ts +1 -1
  33. package/dist/form/field_bindings/BlockFieldBinding.d.ts +1 -1
  34. package/dist/form/field_bindings/MapFieldBinding.d.ts +1 -1
  35. package/dist/form/field_bindings/MarkdownEditorFieldBinding.d.ts +1 -1
  36. package/dist/form/field_bindings/RepeatFieldBinding.d.ts +1 -1
  37. package/dist/form/index.d.ts +16 -16
  38. package/dist/hooks/data/useEntityFetch.d.ts +2 -1
  39. package/dist/hooks/useBreadcrumbsController.d.ts +26 -0
  40. package/dist/hooks/useBuildNavigationController.d.ts +4 -1
  41. package/dist/hooks/useModeController.d.ts +1 -2
  42. package/dist/index.es.js +18213 -16819
  43. package/dist/index.es.js.map +1 -1
  44. package/dist/index.umd.js +18164 -16771
  45. package/dist/index.umd.js.map +1 -1
  46. package/dist/internal/useBuildSideEntityController.d.ts +2 -2
  47. package/dist/internal/useUnsavedChangesDialog.d.ts +7 -9
  48. package/dist/routes/CustomCMSRoute.d.ts +4 -0
  49. package/dist/routes/FireCMSRoute.d.ts +1 -0
  50. package/dist/routes/HomePageRoute.d.ts +3 -0
  51. package/dist/types/collections.d.ts +30 -10
  52. package/dist/types/datasource.d.ts +2 -2
  53. package/dist/types/dialogs_controller.d.ts +7 -3
  54. package/dist/types/entities.d.ts +1 -1
  55. package/dist/types/entity_actions.d.ts +10 -0
  56. package/dist/types/fields.d.ts +9 -2
  57. package/dist/types/navigation.d.ts +29 -12
  58. package/dist/types/plugins.d.ts +1 -0
  59. package/dist/types/properties.d.ts +18 -3
  60. package/dist/types/side_entity_controller.d.ts +6 -1
  61. package/dist/util/builders.d.ts +1 -1
  62. package/dist/util/entity_actions.d.ts +2 -0
  63. package/dist/util/entity_cache.d.ts +23 -0
  64. package/dist/util/index.d.ts +1 -0
  65. package/dist/util/navigation_from_path.d.ts +6 -1
  66. package/dist/util/navigation_utils.d.ts +12 -1
  67. package/dist/util/resolutions.d.ts +6 -1
  68. package/package.json +19 -21
  69. package/src/components/ArrayContainer.tsx +48 -29
  70. package/src/components/CircularProgressCenter.tsx +1 -1
  71. package/src/components/DeleteEntityDialog.tsx +1 -1
  72. package/src/components/EntityCollectionTable/EntityCollectionRowActions.tsx +40 -19
  73. package/src/components/EntityCollectionTable/EntityCollectionTable.tsx +10 -4
  74. package/src/components/EntityCollectionTable/EntityCollectionTableProps.tsx +18 -1
  75. package/src/components/EntityCollectionTable/index.tsx +1 -1
  76. package/src/components/EntityCollectionTable/internal/CollectionTableToolbar.tsx +3 -3
  77. package/src/components/EntityCollectionTable/internal/popup_field/PopupFormField.tsx +5 -11
  78. package/src/components/EntityCollectionView/EntityCollectionView.tsx +83 -41
  79. package/src/components/EntityCollectionView/EntityCollectionViewActions.tsx +4 -2
  80. package/src/components/NotFoundPage.tsx +2 -2
  81. package/src/components/PropertyIdCopyTooltip.tsx +2 -3
  82. package/src/components/ReferenceTable/ReferenceSelectionTable.tsx +11 -6
  83. package/src/components/SelectableTable/SelectableTable.tsx +18 -3
  84. package/src/components/SelectableTable/filters/ReferenceFilterField.tsx +7 -7
  85. package/src/components/UnsavedChangesDialog.tsx +42 -0
  86. package/src/components/VirtualTable/VirtualTable.tsx +19 -2
  87. package/src/components/VirtualTable/VirtualTableProps.tsx +15 -0
  88. package/src/components/VirtualTable/fields/VirtualTableInput.tsx +1 -1
  89. package/src/components/common/default_entity_actions.tsx +26 -37
  90. package/src/components/common/index.ts +1 -1
  91. package/src/components/common/useColumnsIds.tsx +1 -1
  92. package/src/components/common/useDataSourceTableController.tsx +420 -0
  93. package/src/components/common/useDebouncedCallback.tsx +20 -0
  94. package/src/components/common/useScrollRestoration.tsx +68 -0
  95. package/src/contexts/BreacrumbsContext.tsx +38 -0
  96. package/src/contexts/DialogsProvider.tsx +3 -2
  97. package/src/contexts/ModeController.tsx +1 -3
  98. package/src/core/DefaultAppBar.tsx +44 -14
  99. package/src/core/DefaultDrawer.tsx +1 -1
  100. package/src/core/EntityEditView.tsx +278 -1000
  101. package/src/core/EntityEditViewFormActions.tsx +199 -0
  102. package/src/core/EntitySidePanel.tsx +85 -15
  103. package/src/core/FireCMS.tsx +7 -4
  104. package/src/core/FireCMSRouter.tsx +17 -0
  105. package/src/core/NavigationRoutes.tsx +23 -32
  106. package/src/core/SideDialogs.tsx +20 -11
  107. package/src/core/index.tsx +4 -2
  108. package/src/form/EntityForm.tsx +774 -0
  109. package/src/form/EntityFormActions.tsx +169 -0
  110. package/src/form/PropertyFieldBinding.tsx +13 -11
  111. package/src/form/components/FormEntry.tsx +22 -0
  112. package/src/form/components/FormLayout.tsx +16 -0
  113. package/src/form/components/LabelWithIcon.tsx +6 -3
  114. package/src/form/components/StorageUploadProgress.tsx +1 -1
  115. package/src/form/components/index.tsx +2 -0
  116. package/src/form/field_bindings/ArrayCustomShapedFieldBinding.tsx +4 -4
  117. package/src/form/field_bindings/ArrayOfReferencesFieldBinding.tsx +4 -2
  118. package/src/form/field_bindings/BlockFieldBinding.tsx +4 -2
  119. package/src/form/field_bindings/DateTimeFieldBinding.tsx +1 -0
  120. package/src/form/field_bindings/MapFieldBinding.tsx +14 -16
  121. package/src/form/field_bindings/MarkdownEditorFieldBinding.tsx +9 -6
  122. package/src/form/field_bindings/MultiSelectFieldBinding.tsx +1 -1
  123. package/src/form/field_bindings/ReadOnlyFieldBinding.tsx +2 -2
  124. package/src/form/field_bindings/ReferenceFieldBinding.tsx +1 -1
  125. package/src/form/field_bindings/RepeatFieldBinding.tsx +5 -2
  126. package/src/form/field_bindings/SelectFieldBinding.tsx +1 -1
  127. package/src/form/field_bindings/StorageUploadFieldBinding.tsx +6 -4
  128. package/src/form/field_bindings/SwitchFieldBinding.tsx +1 -0
  129. package/src/form/field_bindings/TextFieldBinding.tsx +1 -0
  130. package/src/form/index.tsx +16 -32
  131. package/src/form/validation.ts +12 -6
  132. package/src/hooks/data/save.ts +1 -1
  133. package/src/hooks/data/useCollectionFetch.tsx +1 -1
  134. package/src/hooks/data/useEntityFetch.tsx +5 -1
  135. package/src/hooks/useBreadcrumbsController.tsx +31 -0
  136. package/src/hooks/useBuildModeController.tsx +15 -28
  137. package/src/hooks/useBuildNavigationController.tsx +70 -24
  138. package/src/hooks/useLargeLayout.tsx +0 -35
  139. package/src/hooks/useModeController.tsx +1 -2
  140. package/src/hooks/useResolvedNavigationFrom.tsx +4 -6
  141. package/src/internal/useBuildSideDialogsController.tsx +3 -2
  142. package/src/internal/useBuildSideEntityController.tsx +124 -83
  143. package/src/internal/useUnsavedChangesDialog.tsx +126 -92
  144. package/src/preview/PropertyPreview.tsx +8 -8
  145. package/src/preview/components/UrlComponentPreview.tsx +17 -18
  146. package/src/preview/property_previews/MapPropertyPreview.tsx +3 -2
  147. package/src/routes/CustomCMSRoute.tsx +21 -0
  148. package/src/routes/FireCMSRoute.tsx +235 -0
  149. package/src/routes/HomePageRoute.tsx +17 -0
  150. package/src/types/collections.ts +38 -13
  151. package/src/types/datasource.ts +2 -1
  152. package/src/types/dialogs_controller.tsx +7 -3
  153. package/src/types/entities.ts +1 -1
  154. package/src/types/entity_actions.tsx +12 -0
  155. package/src/types/fields.tsx +13 -2
  156. package/src/types/navigation.ts +36 -16
  157. package/src/types/plugins.tsx +1 -0
  158. package/src/types/properties.ts +21 -3
  159. package/src/types/side_dialogs_controller.tsx +2 -0
  160. package/src/types/side_entity_controller.tsx +6 -1
  161. package/src/util/builders.ts +5 -3
  162. package/src/util/entity_actions.ts +28 -0
  163. package/src/util/entity_cache.ts +204 -0
  164. package/src/util/index.ts +1 -0
  165. package/src/util/join_collections.ts +3 -0
  166. package/src/util/navigation_from_path.ts +13 -6
  167. package/src/util/navigation_utils.ts +53 -1
  168. package/src/util/objects.ts +4 -1
  169. package/src/util/parent_references_from_path.ts +3 -3
  170. package/src/util/resolutions.ts +26 -5
  171. package/src/util/useStorageUploadController.tsx +39 -21
  172. package/src/components/common/useDataSourceEntityCollectionTableController.tsx +0 -236
  173. /package/src/util/{common.tsx → common.ts} +0 -0
@@ -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
@@ -28,7 +29,7 @@ export interface EntitySidePanelProps<M extends Record<string, any> = any> {
28
29
  * Open the entity with a selected sub-collection view. If the panel for this
29
30
  * entity was already open, it is replaced.
30
31
  */
31
- selectedSubPath?: string;
32
+ selectedTab?: string;
32
33
 
33
34
  /**
34
35
  * Use this prop to override the width of the form view.
@@ -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
  /**
@@ -26,8 +26,10 @@ import {
26
26
  * @param collection
27
27
  * @group Builder
28
28
  */
29
- export function buildCollection<M extends Record<string, any> = any,
30
- USER extends User = User>(
29
+ export function buildCollection<
30
+ M extends Record<string, any> = any,
31
+ USER extends User = User>
32
+ (
31
33
  collection: EntityCollection<M, USER>
32
34
  ): EntityCollection<M, USER> {
33
35
  return collection;
@@ -39,7 +41,7 @@ export function buildCollection<M extends Record<string, any> = any,
39
41
  * @param property
40
42
  * @group Builder
41
43
  */
42
- export function buildProperty<T extends CMSType = CMSType, P extends PropertyOrBuilder<T> = PropertyOrBuilder<T>, M extends Record<string, any> = Record<string, any>>(
44
+ export function buildProperty<T extends CMSType = CMSType, P extends PropertyOrBuilder<T> = PropertyOrBuilder<T>, M extends Record<string, any> = any>(
43
45
  property: P
44
46
  ):
45
47
  P extends StringProperty ? StringProperty :
@@ -0,0 +1,28 @@
1
+ import { EntityAction } from "../types";
2
+
3
+ const reservedKeys = ["edit", "copy", "delete"];
4
+
5
+ export function mergeEntityActions(currentActions: EntityAction[], newActions: EntityAction[]): EntityAction[] {
6
+ // given the current actions, replace the ones with the same key
7
+ // and append the new ones
8
+ const updatedActions: EntityAction[] = [];
9
+ currentActions.forEach(action => {
10
+ const newAction = newActions.find(a => a.key === action.key);
11
+ if (newAction) {
12
+ const mergedAction = {
13
+ ...action,
14
+ ...newAction
15
+ }
16
+ updatedActions.push(mergedAction);
17
+ } else {
18
+ updatedActions.push(action);
19
+ }
20
+ });
21
+ newActions.forEach(action => {
22
+ if (!currentActions.find(a => a.key === action.key) && (!action.key || !reservedKeys.includes(action.key))) {
23
+ updatedActions.push(action);
24
+ }
25
+ });
26
+ return updatedActions;
27
+
28
+ }
@@ -0,0 +1,204 @@
1
+ import { EntityReference, GeoPoint, Vector } from "../types";
2
+
3
+ // Define a unique prefix for entity keys in localStorage to avoid key collisions
4
+ const LOCAL_STORAGE_PREFIX = "entity_cache::";
5
+
6
+ // In-memory cache to store entities for quick access
7
+ const entityCache: Map<string, object> = new Map();
8
+
9
+ // Check `localStorage` availability once during initialization
10
+ const isLocalStorageAvailable = typeof localStorage !== "undefined";
11
+
12
+ // Define custom replacer for JSON.stringify
13
+ function customReplacer(key: string): any {
14
+
15
+ // @ts-ignore
16
+ const value = this[key];
17
+
18
+ // Handle Date objects
19
+ // @ts-ignore
20
+ if (value instanceof Date) {
21
+ return { __type: "Date", value: value.toISOString() };
22
+ }
23
+
24
+ // Handle EntityReference
25
+ // @ts-ignore
26
+ if (value instanceof EntityReference) {
27
+ return { __type: "EntityReference", id: value.id, path: value.path };
28
+ }
29
+
30
+ // Handle GeoPoint
31
+ // @ts-ignore
32
+ if (value instanceof GeoPoint) {
33
+ return { __type: "GeoPoint", latitude: value.latitude, longitude: value.longitude };
34
+ }
35
+
36
+ // Handle Vector
37
+ // @ts-ignore
38
+ if (value instanceof Vector) {
39
+ return { __type: "Vector", value: value.value };
40
+ }
41
+
42
+ return value;
43
+ }
44
+
45
+ // Define custom reviver for JSON.parse
46
+ function customReviver(key: string, value: any): any {
47
+ if (value && typeof value === "object" && "__type" in value) {
48
+ switch (value.__type) {
49
+ case "Date":
50
+ return new Date(value.value);
51
+ case "EntityReference":
52
+ return new EntityReference(value.id, value.path);
53
+ case "GeoPoint":
54
+ return new GeoPoint(value.latitude, value.longitude);
55
+ case "Vector":
56
+ return new Vector(value.value);
57
+ default:
58
+ return value;
59
+ }
60
+ }
61
+ return value;
62
+ }
63
+
64
+ // Initialize the in-memory cache by loading entities from `localStorage`
65
+ if (isLocalStorageAvailable) {
66
+ try {
67
+ // Iterate over all keys in localStorage to find those with the specified prefix
68
+ for (let i = 0; i < localStorage.length; i++) {
69
+ const fullKey = localStorage.key(i);
70
+ if (fullKey && fullKey.startsWith(LOCAL_STORAGE_PREFIX)) {
71
+ const path = fullKey.substring(LOCAL_STORAGE_PREFIX.length);
72
+ const entityString = localStorage.getItem(fullKey);
73
+ if (entityString) {
74
+ try {
75
+ const entity: object = JSON.parse(entityString, customReviver);
76
+ entityCache.set(path, entity);
77
+ } catch (parseError) {
78
+ console.error(
79
+ `Failed to parse entity for path "${path}" from localStorage:`,
80
+ parseError
81
+ );
82
+ }
83
+ }
84
+ }
85
+ }
86
+ } catch (error) {
87
+ console.error("Error accessing localStorage during initialization:", error);
88
+ }
89
+ }
90
+
91
+ /**
92
+ * Saves data to the in-memory cache and persists it individually in `localStorage`.
93
+ * @param path - The unique path/key for the data.
94
+ * @param data - The data to cache and persist.
95
+ */
96
+ export function saveEntityToCache(path: string, data: object): void {
97
+ // Update the in-memory cache
98
+ entityCache.set(path, data);
99
+
100
+ // Persist the data individually in localStorage
101
+ if (isLocalStorageAvailable) {
102
+ try {
103
+ const key = LOCAL_STORAGE_PREFIX + path;
104
+ const entityString = JSON.stringify(data, customReplacer);
105
+ localStorage.setItem(key, entityString);
106
+ } catch (error) {
107
+ console.error(
108
+ `Failed to save entity for path "${path}" to localStorage:`,
109
+ error
110
+ );
111
+ }
112
+ }
113
+ }
114
+
115
+ /**
116
+ * Retrieves an entity from the in-memory cache or `localStorage`.
117
+ * If the entity is not in the cache but exists in `localStorage`, it loads it into the cache.
118
+ * @param path - The unique path/key for the entity.
119
+ * @returns The cached entity or `undefined` if not found.
120
+ */
121
+ export function getEntityFromCache(path: string): object | undefined {
122
+
123
+ // Attempt to retrieve the entity from the in-memory cache
124
+ if (entityCache.has(path)) {
125
+ return entityCache.get(path);
126
+ }
127
+
128
+ // If not in the cache, attempt to load it from localStorage
129
+ if (isLocalStorageAvailable) {
130
+ try {
131
+ const key = LOCAL_STORAGE_PREFIX + path;
132
+ const entityString = localStorage.getItem(key);
133
+ if (entityString) {
134
+ const entity: object = JSON.parse(entityString, customReviver);
135
+ entityCache.set(path, entity); // Update the cache
136
+ return entity;
137
+ }
138
+ } catch (error) {
139
+ console.error(
140
+ `Failed to load entity for path "${path}" from localStorage:`,
141
+ error
142
+ );
143
+ }
144
+ }
145
+
146
+ // Entity not found
147
+ return undefined;
148
+ }
149
+
150
+ export function hasEntityInCache(path: string): boolean {
151
+ return entityCache.has(path);
152
+ }
153
+
154
+ /**
155
+ * Removes an entity from both the in-memory cache and `localStorage`.
156
+ * @param path - The unique path/key for the entity to remove.
157
+ */
158
+ export function removeEntityFromCache(path: string): void {
159
+
160
+
161
+ console.debug("Removing entity from cache", path);
162
+
163
+ // Remove from the in-memory cache
164
+ entityCache.delete(path);
165
+
166
+ // Remove from localStorage
167
+ if (isLocalStorageAvailable) {
168
+ try {
169
+ const key = LOCAL_STORAGE_PREFIX + path;
170
+ localStorage.removeItem(key);
171
+ } catch (error) {
172
+ console.error(
173
+ `Failed to remove entity for path "${path}" from localStorage:`,
174
+ error
175
+ );
176
+ }
177
+ }
178
+ }
179
+
180
+ /**
181
+ * Clears the entire in-memory cache and removes all related entities from `localStorage`.
182
+ */
183
+ export function clearEntityCache(): void {
184
+ // Clear the in-memory cache
185
+ entityCache.clear();
186
+
187
+ // Remove all entities with the specified prefix from localStorage
188
+ if (isLocalStorageAvailable) {
189
+ try {
190
+ const keysToRemove: string[] = [];
191
+ for (let i = 0; i < localStorage.length; i++) {
192
+ const fullKey = localStorage.key(i);
193
+ if (fullKey && fullKey.startsWith(LOCAL_STORAGE_PREFIX)) {
194
+ keysToRemove.push(fullKey);
195
+ }
196
+ }
197
+
198
+ // Remove the keys after collecting them to avoid issues while iterating
199
+ keysToRemove.forEach((key) => localStorage.removeItem(key));
200
+ } catch (error) {
201
+ console.error("Failed to clear entity cache from localStorage:", error);
202
+ }
203
+ }
204
+ }
package/src/util/index.ts CHANGED
@@ -7,6 +7,7 @@ export * from "./objects";
7
7
  export * from "./paths";
8
8
  export * from "./regexp";
9
9
  export * from "./navigation_utils";
10
+ export * from "./entity_actions";
10
11
  export * from "./useDebouncedCallback";
11
12
  export * from "./property_utils";
12
13
  export * from "./resolutions";
@@ -115,6 +115,9 @@ export function mergeCollection(target: EntityCollection,
115
115
  if (modifiedCollection)
116
116
  resultCollection = modifiedCollection;
117
117
  }
118
+
119
+ // @ts-ignore
120
+ resultCollection["merged"] = true;
118
121
  return resultCollection
119
122
  }
120
123
 
@@ -11,22 +11,27 @@ export interface NavigationViewEntityInternal<M extends Record<string, any>> {
11
11
  type: "entity";
12
12
  entityId: string;
13
13
  path: string;
14
+ fullPath: string;
14
15
  parentCollection: EntityCollection<M>;
15
16
  }
16
17
 
17
18
  export interface NavigationViewCollectionInternal<M extends Record<string, any>> {
18
19
  type: "collection";
20
+ id: string;
19
21
  path: string;
22
+ fullPath: string;
20
23
  collection: EntityCollection<M>;
21
24
  }
22
25
 
23
26
  export interface NavigationViewEntityCustomInternal<M extends Record<string, any>> {
24
27
  type: "custom_view";
25
28
  path: string;
29
+ fullPath: string;
30
+ entityId: string;
26
31
  view: EntityCustomView<M>;
27
32
  }
28
33
 
29
- export function getNavigationEntriesFromPathInternal(props: {
34
+ export function getNavigationEntriesFromPath(props: {
30
35
  path: string,
31
36
  collections: EntityCollection[] | undefined,
32
37
  currentFullPath?: string,
@@ -56,7 +61,9 @@ export function getNavigationEntriesFromPathInternal(props: {
56
61
 
57
62
  result.push({
58
63
  type: "collection",
64
+ id: collection.id,
59
65
  path: collectionPath,
66
+ fullPath: collectionPath,
60
67
  collection
61
68
  });
62
69
  const restOfThePath = removeInitialAndTrailingSlashes(removeInitialAndTrailingSlashes(path).replace(subpathCombination, ""));
@@ -68,6 +75,7 @@ export function getNavigationEntriesFromPathInternal(props: {
68
75
  type: "entity",
69
76
  entityId,
70
77
  path: collectionPath,
78
+ fullPath: fullPath,
71
79
  parentCollection: collection
72
80
  });
73
81
  if (nextSegments.length > 1) {
@@ -81,16 +89,15 @@ export function getNavigationEntriesFromPathInternal(props: {
81
89
  .filter(Boolean)
82
90
  .find((entry) => entry!.key === newPath);
83
91
  if (customView) {
84
- const path = currentFullPath && currentFullPath.length > 0
85
- ? (currentFullPath + "/" + customView.key)
86
- : customView.key;
87
92
  result.push({
88
93
  type: "custom_view",
89
- path,
94
+ path: collectionPath,
95
+ entityId: entityId,
96
+ fullPath: fullPath + "/" + customView.key,
90
97
  view: customView
91
98
  });
92
99
  } else if (collection.subcollections) {
93
- result.push(...getNavigationEntriesFromPathInternal({
100
+ result.push(...getNavigationEntriesFromPath({
94
101
  path: newPath,
95
102
  collections: collection.subcollections,
96
103
  currentFullPath: fullPath,
@@ -1,4 +1,4 @@
1
- import { EntityCollection } from "../types";
1
+ import { EntityCollection, NavigationController, SideEntityController } from "../types";
2
2
 
3
3
  export function removeInitialAndTrailingSlashes(s: string): string {
4
4
  return removeInitialSlash(removeTrailingSlash(s));
@@ -109,3 +109,55 @@ export function getCollectionPathsCombinations(subpaths: string[]): string[] {
109
109
  return result;
110
110
 
111
111
  }
112
+
113
+ export function navigateToEntity({
114
+ openEntityMode,
115
+ collection,
116
+ entityId,
117
+ copy,
118
+ path,
119
+ selectedTab,
120
+ sideEntityController,
121
+ onClose,
122
+ navigation
123
+ }:
124
+
125
+ {
126
+ openEntityMode: "side_panel" | "full_screen";
127
+ collection?: EntityCollection;
128
+ entityId?: string;
129
+ selectedTab?: string;
130
+ copy?: boolean;
131
+ path: string;
132
+ sideEntityController: SideEntityController;
133
+ onClose?: () => void;
134
+ navigation: NavigationController
135
+ }) {
136
+
137
+ if (openEntityMode === "side_panel") {
138
+
139
+ sideEntityController.open({
140
+ entityId,
141
+ path,
142
+ copy,
143
+ selectedTab,
144
+ collection,
145
+ updateUrl: true,
146
+ onClose
147
+ });
148
+
149
+ } else {
150
+ let to = navigation.buildUrlCollectionPath(entityId ? `${path}/${entityId}` : path);
151
+ if (entityId && selectedTab) {
152
+ to += `/${selectedTab}`;
153
+ }
154
+ if (!entityId) {
155
+ to += "#new";
156
+ }
157
+ if (copy) {
158
+ to += "#copy";
159
+ }
160
+ navigation.navigate(to);
161
+ }
162
+
163
+ }
@@ -18,7 +18,10 @@ export function mergeDeep<T extends Record<any, any>, U extends Record<any, any>
18
18
  if (targetIsObject && isObject(source)) {
19
19
  Object.keys(source).forEach(key => {
20
20
  const sourceElement = source[key];
21
- if (isObject(sourceElement)) {
21
+ if (sourceElement instanceof Date) {
22
+ // Assign a new Date instance with the same time value
23
+ Object.assign(output, { [key]: new Date(sourceElement.getTime()) });
24
+ } else if (isObject(sourceElement)) {
22
25
  if (!(key in target))
23
26
  Object.assign(output, { [key]: sourceElement });
24
27
  else
@@ -22,11 +22,11 @@ export function getParentReferencesFromPath(props: {
22
22
 
23
23
  const collection: EntityCollection<any> | undefined = collections && collections.find((entry) => entry.id === subpathCombination || entry.path === subpathCombination);
24
24
 
25
+ // If we find a collection, we add the reference and continue
25
26
  if (collection) {
26
- const pathOrAlias = collection.id ?? collection.path;
27
27
  const collectionPath = currentFullPath && currentFullPath.length > 0
28
- ? (currentFullPath + "/" + pathOrAlias)
29
- : pathOrAlias;
28
+ ? (currentFullPath + "/" + collection.path)
29
+ : collection.path;
30
30
 
31
31
  const restOfThePath = removeInitialAndTrailingSlashes(removeInitialAndTrailingSlashes(path).replace(subpathCombination, ""));
32
32
  const nextSegments = restOfThePath.length > 0 ? restOfThePath.split("/") : [];
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  ArrayProperty,
3
3
  CMSType,
4
+ CustomizationController,
4
5
  EntityCollection,
5
6
  EntityCustomView,
6
7
  EntityValues,
@@ -218,11 +219,11 @@ export function resolveProperty<T extends CMSType = CMSType, M extends Record<st
218
219
  }
219
220
 
220
221
  export function getArrayResolvedProperties<M>({
221
- propertyKey,
222
- propertyValue,
223
- property,
224
- ...props
225
- }: {
222
+ propertyKey,
223
+ propertyValue,
224
+ property,
225
+ ...props
226
+ }: {
226
227
  propertyValue: any,
227
228
  propertyKey?: string,
228
229
  property: ArrayProperty<any> | ResolvedArrayProperty<any>,
@@ -430,3 +431,23 @@ export function resolveEntityView(entityView: string | EntityCustomView<any>, co
430
431
  return entityView;
431
432
  }
432
433
  }
434
+
435
+ export function resolvedSelectedEntityView<M extends Record<string, any>>(
436
+ customViews: (string | EntityCustomView<M>)[] | undefined,
437
+ customizationController: CustomizationController,
438
+ selectedTab?: string
439
+ ) {
440
+ const resolvedEntityViews = customViews ? customViews
441
+ .map(e => resolveEntityView(e, customizationController.entityViews))
442
+ .filter(Boolean) as EntityCustomView[]
443
+ : [];
444
+
445
+ const selectedEntityView = resolvedEntityViews.find(e => e.key === selectedTab);
446
+ const selectedSecondaryForm = customViews
447
+ && resolvedEntityViews.filter(e => e.includeActions).find(e => e.key === selectedTab);
448
+ return {
449
+ resolvedEntityViews,
450
+ selectedEntityView,
451
+ selectedSecondaryForm
452
+ };
453
+ }
@@ -34,6 +34,7 @@ export interface StorageFieldItem {
34
34
  size: PreviewSize
35
35
  }
36
36
 
37
+
37
38
  export function useStorageUploadController<M extends object>({
38
39
  entityId,
39
40
  entityValues,
@@ -45,17 +46,17 @@ export function useStorageUploadController<M extends object>({
45
46
  disabled,
46
47
  onChange
47
48
  }:
48
- {
49
- entityId: string,
50
- entityValues: EntityValues<M>,
51
- value: string | string[] | null;
52
- path?: string,
53
- propertyKey: string,
54
- property: StringProperty | ArrayProperty<string[]> | ResolvedStringProperty | ResolvedArrayProperty<string[]>,
55
- storageSource: StorageSource,
56
- disabled: boolean,
57
- onChange: (value: string | string[] | null) => void
58
- }) {
49
+ {
50
+ entityId: string,
51
+ entityValues: EntityValues<M>,
52
+ value: string | string[] | null;
53
+ path?: string,
54
+ propertyKey: string,
55
+ property: StringProperty | ArrayProperty<string[]> | ResolvedStringProperty | ResolvedArrayProperty<string[]>,
56
+ storageSource: StorageSource,
57
+ disabled: boolean,
58
+ onChange: (value: string | string[] | null) => void
59
+ }) {
59
60
 
60
61
  const storage: StorageConfig | undefined = property.dataType === "string"
61
62
  ? property.storage
@@ -75,16 +76,7 @@ export function useStorageUploadController<M extends object>({
75
76
  const compression: ImageCompression | undefined = storage?.imageCompression;
76
77
 
77
78
  const internalInitialValue: StorageFieldItem[] =
78
- (multipleFilesSupported
79
- ? (value ?? []) as string[]
80
- : value ? [value as string] : []).map(entry => (
81
- {
82
- id: getRandomId(),
83
- storagePathOrDownloadUrl: entry,
84
- metadata,
85
- size
86
- }
87
- ));
79
+ getInternalInitialValue(multipleFilesSupported, value, metadata, size);
88
80
 
89
81
  const [initialValue, setInitialValue] = useState<string | string[] | null>(value);
90
82
  const [internalValue, setInternalValue] = useState<StorageFieldItem[]>(internalInitialValue);
@@ -226,6 +218,32 @@ export function useStorageUploadController<M extends object>({
226
218
  }
227
219
  }
228
220
 
221
+ function getInternalInitialValue(multipleFilesSupported: boolean,
222
+ value: string | string[] | null,
223
+ metadata: Record<string, any> | undefined,
224
+ size: PreviewSize): StorageFieldItem[] {
225
+ let strings: string[] = [];
226
+ if (multipleFilesSupported) {
227
+ if (Array.isArray(value) && value.every((v) => typeof v === "string")) {
228
+ strings = (value ?? []) as string[];
229
+ }
230
+ } else {
231
+ if (typeof value === "string") {
232
+ strings = value ? [value as string] : [];
233
+ }
234
+ }
235
+
236
+ return strings
237
+ .map(entry => (
238
+ {
239
+ id: getRandomId(),
240
+ storagePathOrDownloadUrl: entry,
241
+ metadata,
242
+ size
243
+ }
244
+ ));
245
+ }
246
+
229
247
  function removeDuplicates(items: StorageFieldItem[]) {
230
248
  return items.filter(
231
249
  (item, i) => {