@firecms/core 3.0.0-canary.24 → 3.0.0-canary.241

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 (387) hide show
  1. package/README.md +3 -3
  2. package/dist/app/AppBar.d.ts +12 -0
  3. package/dist/app/Drawer.d.ts +16 -0
  4. package/dist/app/Scaffold.d.ts +34 -0
  5. package/dist/app/index.d.ts +4 -0
  6. package/dist/app/useApp.d.ts +16 -0
  7. package/dist/components/ArrayContainer.d.ts +30 -6
  8. package/dist/components/CircularProgressCenter.d.ts +1 -1
  9. package/dist/components/ClearFilterSortButton.d.ts +5 -0
  10. package/dist/components/{DeleteConfirmationDialog.d.ts → ConfirmationDialog.d.ts} +1 -1
  11. package/dist/components/EntityCollectionTable/EntityCollectionRowActions.d.ts +13 -13
  12. package/dist/components/EntityCollectionTable/EntityCollectionTable.d.ts +2 -2
  13. package/dist/components/EntityCollectionTable/EntityCollectionTableProps.d.ts +22 -6
  14. package/dist/components/EntityCollectionTable/PropertyTableCell.d.ts +1 -0
  15. package/dist/components/EntityCollectionTable/column_utils.d.ts +1 -2
  16. package/dist/components/EntityCollectionTable/fields/TableReferenceField.d.ts +3 -1
  17. package/dist/components/EntityCollectionTable/index.d.ts +1 -1
  18. package/dist/components/EntityCollectionTable/internal/CollectionTableToolbar.d.ts +1 -4
  19. package/dist/components/EntityCollectionTable/internal/EntityTableCell.d.ts +2 -2
  20. package/dist/components/EntityCollectionTable/internal/popup_field/PopupFormField.d.ts +7 -4
  21. package/dist/components/EntityCollectionView/EntityCollectionView.d.ts +20 -2
  22. package/dist/components/EntityCollectionView/EntityCollectionViewStartActions.d.ts +11 -0
  23. package/dist/components/EntityCollectionView/utils.d.ts +3 -0
  24. package/dist/components/EntityJsonPreview.d.ts +3 -0
  25. package/dist/components/EntityPreview.d.ts +8 -5
  26. package/dist/components/ErrorView.d.ts +1 -1
  27. package/dist/components/HomePage/DefaultHomePage.d.ts +1 -1
  28. package/dist/components/HomePage/NavigationCardBinding.d.ts +1 -1
  29. package/dist/components/PropertyConfigBadge.d.ts +2 -1
  30. package/dist/components/PropertyIdCopyTooltip.d.ts +8 -0
  31. package/dist/components/ReferenceWidget.d.ts +3 -1
  32. package/dist/components/SelectableTable/SelectableTable.d.ts +14 -4
  33. package/dist/components/SelectableTable/filters/ReferenceFilterField.d.ts +2 -1
  34. package/dist/components/UnsavedChangesDialog.d.ts +8 -0
  35. package/dist/components/VirtualTable/VirtualTableProps.d.ts +28 -12
  36. package/dist/components/VirtualTable/types.d.ts +3 -3
  37. package/dist/components/{EntityCollectionTable/internal → common}/default_entity_actions.d.ts +1 -3
  38. package/dist/components/common/index.d.ts +2 -1
  39. package/dist/components/common/table_height.d.ts +5 -0
  40. package/dist/components/common/types.d.ts +4 -6
  41. package/dist/components/common/useColumnsIds.d.ts +3 -1
  42. package/dist/components/common/{useDataSourceEntityCollectionTableController.d.ts → useDataSourceTableController.d.ts} +13 -2
  43. package/dist/components/common/useDebouncedCallback.d.ts +1 -0
  44. package/dist/components/common/useScrollRestoration.d.ts +14 -0
  45. package/dist/components/index.d.ts +5 -2
  46. package/dist/contexts/BreacrumbsContext.d.ts +8 -0
  47. package/dist/core/DefaultAppBar.d.ts +29 -0
  48. package/dist/core/DefaultDrawer.d.ts +19 -0
  49. package/dist/core/DrawerNavigationItem.d.ts +10 -0
  50. package/dist/core/EntityEditView.d.ts +40 -11
  51. package/dist/core/EntityEditViewFormActions.d.ts +2 -0
  52. package/dist/core/FireCMS.d.ts +3 -3
  53. package/dist/core/FireCMSRouter.d.ts +4 -0
  54. package/dist/core/NavigationRoutes.d.ts +2 -3
  55. package/dist/core/SideDialogs.d.ts +4 -2
  56. package/dist/core/index.d.ts +4 -4
  57. package/dist/form/EntityForm.d.ts +36 -64
  58. package/dist/form/EntityFormActions.d.ts +17 -0
  59. package/dist/form/PropertyFieldBinding.d.ts +1 -1
  60. package/dist/form/components/ErrorFocus.d.ts +1 -1
  61. package/dist/form/components/FieldHelperText.d.ts +3 -3
  62. package/dist/form/components/FormEntry.d.ts +6 -0
  63. package/dist/form/components/FormLayout.d.ts +5 -0
  64. package/dist/form/components/LabelWithIcon.d.ts +1 -1
  65. package/dist/form/components/LabelWithIconAndTooltip.d.ts +15 -0
  66. package/dist/form/components/StorageItemPreview.d.ts +4 -4
  67. package/dist/form/components/index.d.ts +3 -1
  68. package/dist/form/field_bindings/ArrayCustomShapedFieldBinding.d.ts +1 -1
  69. package/dist/form/field_bindings/ArrayOfReferencesFieldBinding.d.ts +1 -1
  70. package/dist/form/field_bindings/BlockFieldBinding.d.ts +1 -1
  71. package/dist/form/field_bindings/KeyValueFieldBinding.d.ts +1 -1
  72. package/dist/form/field_bindings/MapFieldBinding.d.ts +1 -1
  73. package/dist/form/field_bindings/MarkdownEditorFieldBinding.d.ts +11 -0
  74. package/dist/form/field_bindings/{MultiSelectBinding.d.ts → MultiSelectFieldBinding.d.ts} +1 -1
  75. package/dist/form/field_bindings/ReadOnlyFieldBinding.d.ts +1 -1
  76. package/dist/form/field_bindings/ReferenceFieldBinding.d.ts +2 -2
  77. package/dist/form/field_bindings/RepeatFieldBinding.d.ts +1 -1
  78. package/dist/form/field_bindings/SelectFieldBinding.d.ts +1 -1
  79. package/dist/form/field_bindings/StorageUploadFieldBinding.d.ts +3 -5
  80. package/dist/form/field_bindings/SwitchFieldBinding.d.ts +1 -2
  81. package/dist/form/field_bindings/TextFieldBinding.d.ts +1 -1
  82. package/dist/form/index.d.ts +16 -18
  83. package/dist/form/useClearRestoreValue.d.ts +2 -2
  84. package/dist/hooks/data/delete.d.ts +4 -4
  85. package/dist/hooks/data/save.d.ts +4 -5
  86. package/dist/hooks/data/useCollectionFetch.d.ts +1 -1
  87. package/dist/hooks/data/useEntityFetch.d.ts +4 -3
  88. package/dist/hooks/index.d.ts +1 -0
  89. package/dist/hooks/useAuthController.d.ts +1 -1
  90. package/dist/hooks/useBreadcrumbsController.d.ts +26 -0
  91. package/dist/hooks/useBuildNavigationController.d.ts +7 -12
  92. package/dist/hooks/useFireCMSContext.d.ts +1 -1
  93. package/dist/hooks/useModeController.d.ts +1 -2
  94. package/dist/hooks/useProjectLog.d.ts +8 -2
  95. package/dist/hooks/useResolvedNavigationFrom.d.ts +3 -3
  96. package/dist/hooks/useValidateAuthenticator.d.ts +4 -8
  97. package/dist/index.d.ts +1 -0
  98. package/dist/index.es.js +21578 -13895
  99. package/dist/index.es.js.map +1 -1
  100. package/dist/index.umd.js +24366 -588
  101. package/dist/index.umd.js.map +1 -1
  102. package/dist/internal/useBuildDataSource.d.ts +3 -17
  103. package/dist/internal/useBuildSideEntityController.d.ts +3 -3
  104. package/dist/internal/useUnsavedChangesDialog.d.ts +7 -9
  105. package/dist/preview/PropertyPreviewProps.d.ts +6 -1
  106. package/dist/preview/components/EnumValuesChip.d.ts +1 -1
  107. package/dist/preview/components/ReferencePreview.d.ts +3 -2
  108. package/dist/preview/components/StorageThumbnail.d.ts +2 -1
  109. package/dist/preview/components/UrlComponentPreview.d.ts +2 -1
  110. package/dist/preview/util.d.ts +3 -3
  111. package/dist/routes/CustomCMSRoute.d.ts +4 -0
  112. package/dist/routes/FireCMSRoute.d.ts +1 -0
  113. package/dist/routes/HomePageRoute.d.ts +3 -0
  114. package/dist/types/auth.d.ts +8 -10
  115. package/dist/types/collections.d.ts +97 -23
  116. package/dist/types/datasource.d.ts +52 -36
  117. package/dist/types/dialogs_controller.d.ts +7 -3
  118. package/dist/types/entities.d.ts +7 -2
  119. package/dist/types/entity_actions.d.ts +28 -4
  120. package/dist/types/entity_callbacks.d.ts +16 -16
  121. package/dist/types/entity_overrides.d.ts +2 -2
  122. package/dist/types/export_import.d.ts +4 -4
  123. package/dist/types/fields.d.ts +74 -42
  124. package/dist/types/firecms.d.ts +8 -3
  125. package/dist/types/firecms_context.d.ts +1 -1
  126. package/dist/types/index.d.ts +0 -1
  127. package/dist/types/navigation.d.ts +41 -14
  128. package/dist/types/permissions.d.ts +4 -4
  129. package/dist/types/plugins.d.ts +36 -12
  130. package/dist/types/properties.d.ts +73 -24
  131. package/dist/types/property_config.d.ts +0 -2
  132. package/dist/types/side_dialogs_controller.d.ts +10 -0
  133. package/dist/types/side_entity_controller.d.ts +10 -1
  134. package/dist/types/storage.d.ts +86 -3
  135. package/dist/types/user.d.ts +1 -0
  136. package/dist/util/builders.d.ts +3 -3
  137. package/dist/util/callbacks.d.ts +2 -0
  138. package/dist/util/createFormexStub.d.ts +2 -0
  139. package/dist/util/entities.d.ts +3 -3
  140. package/dist/util/entity_actions.d.ts +2 -0
  141. package/dist/util/entity_cache.d.ts +23 -0
  142. package/dist/util/icon_list.d.ts +5 -1
  143. package/dist/util/icon_synonyms.d.ts +1 -98
  144. package/dist/util/icons.d.ts +6 -3
  145. package/dist/util/index.d.ts +3 -0
  146. package/dist/util/navigation_from_path.d.ts +6 -1
  147. package/dist/util/navigation_utils.d.ts +15 -3
  148. package/dist/util/objects.d.ts +2 -1
  149. package/dist/util/permissions.d.ts +4 -4
  150. package/dist/util/plurals.d.ts +0 -2
  151. package/dist/util/property_utils.d.ts +4 -4
  152. package/dist/util/references.d.ts +2 -2
  153. package/dist/util/resolutions.d.ts +41 -17
  154. package/dist/util/storage.d.ts +23 -2
  155. package/dist/util/useStorageUploadController.d.ts +3 -3
  156. package/package.json +62 -48
  157. package/src/app/AppBar.tsx +18 -0
  158. package/src/app/Drawer.tsx +24 -0
  159. package/src/app/Scaffold.tsx +253 -0
  160. package/src/app/index.ts +4 -0
  161. package/src/app/useApp.tsx +32 -0
  162. package/src/components/ArrayContainer.tsx +149 -46
  163. package/src/components/CircularProgressCenter.tsx +2 -2
  164. package/src/components/ClearFilterSortButton.tsx +41 -0
  165. package/src/components/{DeleteConfirmationDialog.tsx → ConfirmationDialog.tsx} +11 -11
  166. package/src/components/DeleteEntityDialog.tsx +13 -20
  167. package/src/components/EntityCollectionTable/EntityCollectionRowActions.tsx +59 -40
  168. package/src/components/EntityCollectionTable/EntityCollectionTable.tsx +38 -31
  169. package/src/components/EntityCollectionTable/EntityCollectionTableProps.tsx +30 -9
  170. package/src/components/EntityCollectionTable/PropertyTableCell.tsx +48 -40
  171. package/src/components/EntityCollectionTable/column_utils.tsx +3 -3
  172. package/src/components/EntityCollectionTable/fields/TableReferenceField.tsx +30 -16
  173. package/src/components/EntityCollectionTable/fields/TableStorageUpload.tsx +19 -17
  174. package/src/components/EntityCollectionTable/index.tsx +1 -1
  175. package/src/components/EntityCollectionTable/internal/CollectionTableToolbar.tsx +32 -37
  176. package/src/components/EntityCollectionTable/internal/EntityTableCell.tsx +36 -34
  177. package/src/components/EntityCollectionTable/internal/EntityTableCellActions.tsx +20 -8
  178. package/src/components/EntityCollectionTable/internal/popup_field/PopupFormField.tsx +84 -80
  179. package/src/components/EntityCollectionView/EntityCollectionView.tsx +229 -117
  180. package/src/components/EntityCollectionView/EntityCollectionViewActions.tsx +4 -2
  181. package/src/components/EntityCollectionView/EntityCollectionViewStartActions.tsx +68 -0
  182. package/src/components/EntityCollectionView/useSelectionController.tsx +20 -7
  183. package/src/components/EntityCollectionView/utils.ts +19 -0
  184. package/src/components/EntityJsonPreview.tsx +66 -0
  185. package/src/components/EntityPreview.tsx +80 -59
  186. package/src/components/EntityView.tsx +13 -10
  187. package/src/components/ErrorView.tsx +4 -4
  188. package/src/components/HomePage/DefaultHomePage.tsx +27 -20
  189. package/src/components/HomePage/FavouritesView.tsx +6 -11
  190. package/src/components/HomePage/NavigationCard.tsx +3 -3
  191. package/src/components/HomePage/NavigationCardBinding.tsx +5 -10
  192. package/src/components/HomePage/NavigationGroup.tsx +2 -2
  193. package/src/components/HomePage/SmallNavigationCard.tsx +5 -6
  194. package/src/components/NotFoundPage.tsx +2 -2
  195. package/src/components/PropertyConfigBadge.tsx +9 -3
  196. package/src/components/PropertyIdCopyTooltip.tsx +47 -0
  197. package/src/components/ReferenceTable/ReferenceSelectionTable.tsx +21 -13
  198. package/src/components/ReferenceWidget.tsx +21 -11
  199. package/src/components/SearchIconsView.tsx +10 -7
  200. package/src/components/SelectableTable/SelectableTable.tsx +157 -145
  201. package/src/components/SelectableTable/filters/BooleanFilterField.tsx +2 -3
  202. package/src/components/SelectableTable/filters/DateTimeFilterField.tsx +25 -8
  203. package/src/components/SelectableTable/filters/ReferenceFilterField.tsx +36 -12
  204. package/src/components/SelectableTable/filters/StringNumberFilterField.tsx +92 -23
  205. package/src/components/UnsavedChangesDialog.tsx +42 -0
  206. package/src/components/VirtualTable/VirtualTable.tsx +130 -51
  207. package/src/components/VirtualTable/VirtualTableCell.tsx +1 -9
  208. package/src/components/VirtualTable/VirtualTableHeader.tsx +10 -10
  209. package/src/components/VirtualTable/VirtualTableHeaderRow.tsx +2 -2
  210. package/src/components/VirtualTable/VirtualTableProps.tsx +33 -14
  211. package/src/components/VirtualTable/VirtualTableRow.tsx +5 -6
  212. package/src/components/VirtualTable/fields/VirtualTableDateField.tsx +5 -5
  213. package/src/components/VirtualTable/fields/VirtualTableInput.tsx +3 -2
  214. package/src/components/VirtualTable/fields/VirtualTableNumberInput.tsx +2 -1
  215. package/src/components/VirtualTable/fields/VirtualTableSelect.tsx +16 -28
  216. package/src/components/VirtualTable/types.tsx +2 -3
  217. package/src/components/{EntityCollectionTable/internal → common}/default_entity_actions.tsx +44 -40
  218. package/src/components/common/index.ts +2 -1
  219. package/src/components/{VirtualTable/common.tsx → common/table_height.tsx} +5 -2
  220. package/src/components/common/types.tsx +4 -6
  221. package/src/components/common/useColumnsIds.tsx +24 -3
  222. package/src/components/common/useDataSourceTableController.tsx +420 -0
  223. package/src/components/common/useDebouncedCallback.tsx +20 -0
  224. package/src/components/common/useScrollRestoration.tsx +68 -0
  225. package/src/components/common/useTableSearchHelper.ts +53 -12
  226. package/src/components/index.tsx +6 -2
  227. package/src/contexts/BreacrumbsContext.tsx +38 -0
  228. package/src/contexts/DialogsProvider.tsx +5 -4
  229. package/src/contexts/ModeController.tsx +1 -3
  230. package/src/contexts/SnackbarProvider.tsx +2 -0
  231. package/src/core/DefaultAppBar.tsx +219 -0
  232. package/src/core/DefaultDrawer.tsx +185 -0
  233. package/src/core/DrawerNavigationItem.tsx +66 -0
  234. package/src/core/EntityEditView.tsx +406 -478
  235. package/src/core/EntityEditViewFormActions.tsx +199 -0
  236. package/src/core/EntitySidePanel.tsx +95 -19
  237. package/src/core/FireCMS.tsx +72 -58
  238. package/src/core/FireCMSRouter.tsx +17 -0
  239. package/src/core/NavigationRoutes.tsx +28 -38
  240. package/src/core/SideDialogs.tsx +22 -12
  241. package/src/core/field_configs.tsx +11 -12
  242. package/src/core/index.tsx +6 -5
  243. package/src/form/EntityForm.tsx +589 -535
  244. package/src/form/EntityFormActions.tsx +169 -0
  245. package/src/form/PropertyFieldBinding.tsx +89 -45
  246. package/src/form/components/CustomIdField.tsx +6 -2
  247. package/src/form/components/FieldHelperText.tsx +4 -4
  248. package/src/form/components/FormEntry.tsx +22 -0
  249. package/src/form/components/FormLayout.tsx +16 -0
  250. package/src/form/components/LabelWithIcon.tsx +30 -19
  251. package/src/form/components/LabelWithIconAndTooltip.tsx +28 -0
  252. package/src/form/components/StorageItemPreview.tsx +22 -12
  253. package/src/form/components/StorageUploadProgress.tsx +4 -5
  254. package/src/form/components/index.tsx +3 -1
  255. package/src/form/field_bindings/ArrayCustomShapedFieldBinding.tsx +34 -19
  256. package/src/form/field_bindings/ArrayOfReferencesFieldBinding.tsx +48 -35
  257. package/src/form/field_bindings/BlockFieldBinding.tsx +56 -34
  258. package/src/form/field_bindings/DateTimeFieldBinding.tsx +18 -14
  259. package/src/form/field_bindings/KeyValueFieldBinding.tsx +61 -52
  260. package/src/form/field_bindings/MapFieldBinding.tsx +71 -54
  261. package/src/form/field_bindings/MarkdownEditorFieldBinding.tsx +157 -0
  262. package/src/form/field_bindings/{MultiSelectBinding.tsx → MultiSelectFieldBinding.tsx} +25 -20
  263. package/src/form/field_bindings/ReadOnlyFieldBinding.tsx +11 -16
  264. package/src/form/field_bindings/ReferenceFieldBinding.tsx +42 -31
  265. package/src/form/field_bindings/RepeatFieldBinding.tsx +62 -35
  266. package/src/form/field_bindings/SelectFieldBinding.tsx +23 -15
  267. package/src/form/field_bindings/StorageUploadFieldBinding.tsx +47 -52
  268. package/src/form/field_bindings/SwitchFieldBinding.tsx +29 -24
  269. package/src/form/field_bindings/TextFieldBinding.tsx +28 -24
  270. package/src/form/index.tsx +16 -37
  271. package/src/form/useClearRestoreValue.tsx +2 -2
  272. package/src/form/validation.ts +13 -23
  273. package/src/hooks/data/delete.ts +6 -5
  274. package/src/hooks/data/save.ts +32 -33
  275. package/src/hooks/data/useCollectionFetch.tsx +3 -3
  276. package/src/hooks/data/useDataSource.tsx +11 -3
  277. package/src/hooks/data/useEntityFetch.tsx +10 -6
  278. package/src/hooks/index.tsx +1 -0
  279. package/src/hooks/useAuthController.tsx +1 -1
  280. package/src/hooks/useBreadcrumbsController.tsx +31 -0
  281. package/src/hooks/useBuildLocalConfigurationPersistence.tsx +8 -10
  282. package/src/hooks/useBuildModeController.tsx +22 -29
  283. package/src/hooks/useBuildNavigationController.tsx +194 -68
  284. package/src/hooks/useFireCMSContext.tsx +3 -33
  285. package/src/hooks/useLargeLayout.tsx +0 -35
  286. package/src/hooks/useModeController.tsx +1 -2
  287. package/src/hooks/useProjectLog.tsx +32 -10
  288. package/src/hooks/useResolvedNavigationFrom.tsx +10 -12
  289. package/src/hooks/useValidateAuthenticator.tsx +17 -37
  290. package/src/index.ts +1 -0
  291. package/src/internal/useBuildDataSource.ts +79 -85
  292. package/src/internal/useBuildSideDialogsController.tsx +4 -2
  293. package/src/internal/useBuildSideEntityController.tsx +201 -75
  294. package/src/internal/useUnsavedChangesDialog.tsx +127 -91
  295. package/src/preview/PropertyPreview.tsx +20 -25
  296. package/src/preview/PropertyPreviewProps.tsx +7 -1
  297. package/src/preview/components/BooleanPreview.tsx +2 -2
  298. package/src/preview/components/EmptyValue.tsx +1 -1
  299. package/src/preview/components/EnumValuesChip.tsx +2 -2
  300. package/src/preview/components/ImagePreview.tsx +26 -37
  301. package/src/preview/components/ReferencePreview.tsx +23 -34
  302. package/src/preview/components/StorageThumbnail.tsx +5 -1
  303. package/src/preview/components/UrlComponentPreview.tsx +60 -28
  304. package/src/preview/property_previews/ArrayOfMapsPreview.tsx +6 -6
  305. package/src/preview/property_previews/ArrayOfReferencesPreview.tsx +7 -5
  306. package/src/preview/property_previews/ArrayOfStorageComponentsPreview.tsx +5 -4
  307. package/src/preview/property_previews/ArrayOfStringsPreview.tsx +4 -4
  308. package/src/preview/property_previews/ArrayOneOfPreview.tsx +7 -6
  309. package/src/preview/property_previews/ArrayPropertyPreview.tsx +7 -6
  310. package/src/preview/property_previews/MapPropertyPreview.tsx +12 -11
  311. package/src/preview/property_previews/SkeletonPropertyComponent.tsx +13 -13
  312. package/src/preview/property_previews/StringPropertyPreview.tsx +3 -3
  313. package/src/preview/util.ts +10 -10
  314. package/src/routes/CustomCMSRoute.tsx +21 -0
  315. package/src/routes/FireCMSRoute.tsx +246 -0
  316. package/src/routes/HomePageRoute.tsx +17 -0
  317. package/src/types/auth.tsx +9 -13
  318. package/src/types/collections.ts +118 -28
  319. package/src/types/customization_controller.tsx +0 -1
  320. package/src/types/datasource.ts +61 -43
  321. package/src/types/dialogs_controller.tsx +7 -3
  322. package/src/types/entities.ts +12 -2
  323. package/src/types/entity_actions.tsx +32 -7
  324. package/src/types/entity_callbacks.ts +18 -18
  325. package/src/types/entity_overrides.tsx +2 -2
  326. package/src/types/export_import.ts +4 -4
  327. package/src/types/fields.tsx +85 -46
  328. package/src/types/firecms.tsx +9 -4
  329. package/src/types/firecms_context.tsx +1 -1
  330. package/src/types/index.ts +0 -1
  331. package/src/types/navigation.ts +49 -18
  332. package/src/types/permissions.ts +5 -5
  333. package/src/types/plugins.tsx +42 -14
  334. package/src/types/properties.ts +87 -26
  335. package/src/types/property_config.tsx +0 -2
  336. package/src/types/side_dialogs_controller.tsx +15 -0
  337. package/src/types/side_entity_controller.tsx +11 -1
  338. package/src/types/storage.ts +94 -3
  339. package/src/types/user.ts +2 -0
  340. package/src/util/builders.ts +10 -8
  341. package/src/util/callbacks.ts +119 -0
  342. package/src/util/createFormexStub.tsx +62 -0
  343. package/src/util/entities.ts +9 -6
  344. package/src/util/entity_actions.ts +28 -0
  345. package/src/util/entity_cache.ts +204 -0
  346. package/src/util/enums.ts +1 -1
  347. package/src/util/icon_list.ts +16 -10
  348. package/src/util/icon_synonyms.ts +3 -100
  349. package/src/util/icons.tsx +17 -7
  350. package/src/util/index.ts +3 -0
  351. package/src/util/join_collections.ts +6 -1
  352. package/src/util/make_properties_editable.ts +13 -5
  353. package/src/util/navigation_from_path.ts +18 -7
  354. package/src/util/navigation_utils.ts +141 -25
  355. package/src/util/objects.ts +52 -28
  356. package/src/util/parent_references_from_path.ts +3 -3
  357. package/src/util/permissions.ts +9 -8
  358. package/src/util/plurals.ts +0 -2
  359. package/src/util/property_utils.tsx +17 -6
  360. package/src/util/references.ts +19 -8
  361. package/src/util/resolutions.ts +110 -48
  362. package/src/util/storage.ts +79 -21
  363. package/src/util/strings.ts +2 -2
  364. package/src/util/useStorageUploadController.tsx +91 -28
  365. package/dist/components/FireCMSAppBar.d.ts +0 -26
  366. package/dist/components/PropertyIdCopyTooltipContent.d.ts +0 -3
  367. package/dist/components/VirtualTable/common.d.ts +0 -2
  368. package/dist/core/Drawer.d.ts +0 -23
  369. package/dist/core/Scaffold.d.ts +0 -55
  370. package/dist/core/SideEntityView.d.ts +0 -7
  371. package/dist/form/components/FormikArrayContainer.d.ts +0 -18
  372. package/dist/form/field_bindings/MarkdownFieldBinding.d.ts +0 -9
  373. package/dist/internal/useBuildCustomizationController.d.ts +0 -2
  374. package/dist/internal/useLocaleConfig.d.ts +0 -1
  375. package/dist/types/appcheck.d.ts +0 -26
  376. package/src/components/FireCMSAppBar.tsx +0 -165
  377. package/src/components/PropertyIdCopyTooltipContent.tsx +0 -28
  378. package/src/components/common/useDataSourceEntityCollectionTableController.tsx +0 -225
  379. package/src/core/Drawer.tsx +0 -191
  380. package/src/core/Scaffold.tsx +0 -281
  381. package/src/core/SideEntityView.tsx +0 -38
  382. package/src/form/components/FormikArrayContainer.tsx +0 -44
  383. package/src/form/field_bindings/MarkdownFieldBinding.tsx +0 -695
  384. package/src/internal/useBuildCustomizationController.tsx +0 -5
  385. package/src/internal/useLocaleConfig.tsx +0 -18
  386. package/src/types/appcheck.ts +0 -29
  387. /package/src/util/{common.tsx → common.ts} +0 -0
@@ -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));
@@ -32,42 +32,103 @@ export function getLastSegment(path: string) {
32
32
  }
33
33
 
34
34
  export function resolveCollectionPathIds(path: string, allCollections: EntityCollection[]): string {
35
-
36
- const cleanPath = removeInitialAndTrailingSlashes(path);
37
- const subpaths = cleanPath.split("/");
38
- if (subpaths.length % 2 === 0) {
39
- throw Error(`resolveCollectionPathAliases: Collection paths must have an odd number of segments: ${path}`);
35
+ let remainingPath = removeInitialAndTrailingSlashes(path);
36
+ if (!remainingPath) {
37
+ return "";
40
38
  }
41
39
 
42
- const aliasedCollection = allCollections.find((col) => col.id === subpaths[0]);
43
- let resolvedAliased;
44
- if (aliasedCollection) {
45
- resolvedAliased = aliasedCollection.path;
46
- }
40
+ let currentCollections: EntityCollection[] | undefined = allCollections;
41
+ const resolvedPathParts: string[] = [];
47
42
 
48
- if (subpaths.length > 1) {
49
- const segmentCollection = getCollectionByPathOrId(resolvedAliased ?? subpaths[0], allCollections);
50
- if (!segmentCollection?.subcollections) {
51
- return cleanPath;
43
+ while (remainingPath.length > 0) {
44
+ if (!currentCollections || currentCollections.length === 0) {
45
+ // We have remaining path segments but no more collections to match against
46
+ console.warn(`resolveCollectionPathIds: Path structure implies subcollections, but none found before segment starting with "${remainingPath}" in original path "${path}". Appending remaining original path.`);
47
+ resolvedPathParts.push(remainingPath);
48
+ remainingPath = ""; // Stop processing
49
+ break;
50
+ }
51
+
52
+ let foundMatch = false;
53
+ // Sort potential matches by length descending to prioritize longer matches (e.g., "a/b" over "a")
54
+ const potentialMatches: { col: EntityCollection; match: string; }[] = currentCollections
55
+ .flatMap(col => [{
56
+ col,
57
+ match: col.path
58
+ }, {
59
+ col,
60
+ match: col.id
61
+ }])
62
+ .filter(p => p.match && remainingPath.startsWith(p.match))
63
+ .sort((a, b) => b.match.length - a.match.length);
64
+
65
+ if (potentialMatches.length > 0) {
66
+ const {
67
+ col: foundCollection,
68
+ match: matchString
69
+ } = potentialMatches[0];
70
+
71
+ resolvedPathParts.push(foundCollection.path); // Use the defined path
72
+ remainingPath = removeInitialSlash(remainingPath.substring(matchString.length));
73
+
74
+ // Check if we are at the end of the path
75
+ if (remainingPath.length === 0) {
76
+ foundMatch = true;
77
+ break; // Path ends with a collection segment
78
+ }
79
+
80
+ // The next segment must be an entity ID
81
+ const idSeparatorIndex = remainingPath.indexOf("/");
82
+ let entityId: string;
83
+ if (idSeparatorIndex > -1) {
84
+ entityId = remainingPath.substring(0, idSeparatorIndex);
85
+ remainingPath = remainingPath.substring(idSeparatorIndex + 1);
86
+ } else {
87
+ // This should not happen if the original path is valid (odd segments)
88
+ // but handle it defensively: assume the rest is the ID
89
+ entityId = remainingPath;
90
+ remainingPath = "";
91
+ console.warn(`resolveCollectionPathIds: Path seems to end with an entity ID "${entityId}" instead of a collection segment in original path "${path}". This might indicate an invalid input path.`);
92
+ // Even if it ends here, we still need to push the ID
93
+ }
94
+
95
+ resolvedPathParts.push(entityId); // Append entity ID
96
+ currentCollections = foundCollection.subcollections; // Move to subcollections
97
+ foundMatch = true;
98
+
99
+ if (!currentCollections && remainingPath.length > 0) {
100
+ // Warn if the path continues but no subcollections were defined
101
+ console.warn(`resolveCollectionPathIds: Path continues after entity ID "${entityId}", but no subcollections are defined for the preceding collection "${foundCollection.path}" in path "${path}". Appending remaining original path.`);
102
+ resolvedPathParts.push(remainingPath); // Append the rest
103
+ remainingPath = ""; // Stop processing
104
+ break;
105
+ }
106
+
107
+ }
108
+
109
+ if (!foundMatch) {
110
+ // Collection definition not found for the start of the remaining path
111
+ console.warn(`resolveCollectionPathIds: Collection definition not found for segment starting with "${remainingPath}" in original path "${path}". Appending remaining original path.`);
112
+ resolvedPathParts.push(remainingPath); // Append the rest
113
+ remainingPath = ""; // Stop processing
114
+ break;
52
115
  }
53
- const restOfThePath = cleanPath.split("/").slice(2).join("/");
54
- return (resolvedAliased ?? subpaths[0]) + "/" + subpaths[1] + "/" + resolveCollectionPathIds(restOfThePath, segmentCollection.subcollections);
55
- } else {
56
- return resolvedAliased ?? cleanPath;
57
116
  }
117
+
118
+ return resolvedPathParts.join("/");
58
119
  }
59
120
 
60
121
  /**
61
122
  * Find the corresponding view at any depth for a given path.
62
123
  * Note that path or segments of the paths can be collection aliases.
63
- * @param pathOrAlias
124
+ * @param pathOrId
64
125
  * @param collections
65
126
  */
66
- export function getCollectionByPathOrId(pathOrAlias: string, collections: EntityCollection[]): EntityCollection | undefined {
127
+ export function getCollectionByPathOrId(pathOrId: string, collections: EntityCollection[]): EntityCollection | undefined {
67
128
 
68
- const subpaths = removeInitialAndTrailingSlashes(pathOrAlias).split("/");
129
+ const subpaths = removeInitialAndTrailingSlashes(pathOrId).split("/");
69
130
  if (subpaths.length % 2 === 0) {
70
- throw Error(`getCollectionByPathOrAlias: Collection paths must have an odd number of segments: ${pathOrAlias}`);
131
+ throw Error(`getCollectionByPathOrId: Collection paths must have an odd number of segments: ${pathOrId}`);
71
132
  }
72
133
 
73
134
  const subpathCombinations = getCollectionPathsCombinations(subpaths);
@@ -80,10 +141,10 @@ export function getCollectionByPathOrId(pathOrAlias: string, collections: Entity
80
141
 
81
142
  if (navigationEntry) {
82
143
 
83
- if (subpathCombination === pathOrAlias) {
144
+ if (subpathCombination === pathOrId) {
84
145
  result = navigationEntry;
85
146
  } else if (navigationEntry.subcollections) {
86
- const newPath = pathOrAlias.replace(subpathCombination, "").split("/").slice(2).join("/");
147
+ const newPath = pathOrId.replace(subpathCombination, "").split("/").slice(2).join("/");
87
148
  if (newPath.length > 0)
88
149
  result = getCollectionByPathOrId(newPath, navigationEntry.subcollections);
89
150
  }
@@ -109,3 +170,58 @@ export function getCollectionPathsCombinations(subpaths: string[]): string[] {
109
170
  return result;
110
171
 
111
172
  }
173
+
174
+ export function navigateToEntity({
175
+ openEntityMode,
176
+ collection,
177
+ entityId,
178
+ copy,
179
+ path,
180
+ fullIdPath,
181
+ selectedTab,
182
+ sideEntityController,
183
+ onClose,
184
+ navigation
185
+ }:
186
+
187
+ {
188
+ openEntityMode: "side_panel" | "full_screen";
189
+ collection?: EntityCollection;
190
+ entityId?: string;
191
+ selectedTab?: string;
192
+ copy?: boolean;
193
+ path: string;
194
+ fullIdPath?: string;
195
+ sideEntityController: SideEntityController;
196
+ onClose?: () => void;
197
+ navigation: NavigationController
198
+ }) {
199
+
200
+ if (openEntityMode === "side_panel") {
201
+
202
+ sideEntityController.open({
203
+ entityId,
204
+ path: fullIdPath ?? path,
205
+ // fullIdPath,
206
+ copy,
207
+ selectedTab,
208
+ collection,
209
+ updateUrl: true,
210
+ onClose
211
+ });
212
+
213
+ } else {
214
+ let to = navigation.buildUrlCollectionPath(entityId ? `${fullIdPath ?? path}/${entityId}` : fullIdPath ?? path);
215
+ if (entityId && selectedTab) {
216
+ to += `/${selectedTab}`;
217
+ }
218
+ if (!entityId) {
219
+ to += "#new";
220
+ }
221
+ if (copy) {
222
+ to += "#copy";
223
+ }
224
+ navigation.navigate(to);
225
+ }
226
+
227
+ }
@@ -12,38 +12,32 @@ export function isObject(item: any) {
12
12
  return item && typeof item === "object" && !Array.isArray(item);
13
13
  }
14
14
 
15
- export function mergeDeep<T extends object>(target: T, source: any): T {
15
+ export function mergeDeep<T extends Record<any, any>, U extends Record<any, any>>(target: T, source: U, ignoreUndefined: boolean = false): T & U {
16
16
  const targetIsObject = isObject(target);
17
- const output: T = targetIsObject ? { ...target } : target;
17
+ const output = targetIsObject ? { ...target } : target;
18
18
  if (targetIsObject && isObject(source)) {
19
19
  Object.keys(source).forEach(key => {
20
- if (isObject(source[key])) {
20
+ const sourceElement = source[key];
21
+ // Skip undefined values when ignoreUndefined is true
22
+ if (ignoreUndefined && sourceElement === undefined) {
23
+ return;
24
+ }
25
+ if (sourceElement instanceof Date) {
26
+ // Assign a new Date instance with the same time value
27
+ Object.assign(output, { [key]: new Date(sourceElement.getTime()) });
28
+ } else if (isObject(sourceElement)) {
21
29
  if (!(key in target))
22
- Object.assign(output, { [key]: source[key] });
30
+ Object.assign(output, { [key]: sourceElement });
23
31
  else
24
- (output as any)[key] = mergeDeep((target as any)[key], source[key]);
32
+ (output as any)[key] = mergeDeep((target as any)[key], sourceElement);
25
33
  } else {
26
- Object.assign(output, { [key]: source[key] });
34
+ Object.assign(output, { [key]: sourceElement });
27
35
  }
28
36
  });
29
37
  }
30
- return output;
38
+ return output as T;
31
39
  }
32
40
 
33
- // export function getValueInPath(o: object | undefined, path: string): any {
34
- // if (!o) return undefined;
35
- // if (typeof o === "object") {
36
- // if (path in o) {
37
- // return (o as any)[path];
38
- // }
39
- // if (path.includes(".")) {
40
- // const pathSegments = path.split(".");
41
- // return getValueInPath((o as any)[pathSegments[0]], pathSegments.slice(1).join("."))
42
- // }
43
- // }
44
- // return undefined;
45
- // }
46
-
47
41
  export function getValueInPath(o: object | undefined, path: string): any {
48
42
  if (!o) return undefined;
49
43
  if (typeof o === "object") {
@@ -138,6 +132,26 @@ export function removeUndefined(value: any, removeEmptyStrings?: boolean): any {
138
132
  return value;
139
133
  }
140
134
 
135
+ export function removeNulls(value: any): any {
136
+ if (typeof value === "function") {
137
+ return value;
138
+ }
139
+ if (Array.isArray(value)) {
140
+ return value.map((v: any) => removeNulls(v));
141
+ }
142
+ if (typeof value === "object") {
143
+ const res: object = {};
144
+ if (value === null)
145
+ return value;
146
+ Object.keys(value).forEach((key) => {
147
+ if (value[key] !== null)
148
+ (res as any)[key] = removeNulls(value[key]);
149
+ });
150
+ return res;
151
+ }
152
+ return value;
153
+ }
154
+
141
155
  export function isEmptyObject(obj: object) {
142
156
  return obj &&
143
157
  Object.getPrototypeOf(obj) === Object.prototype &&
@@ -154,15 +168,25 @@ export function removePropsIfExisting(source: any, comparison: any) {
154
168
 
155
169
  const res = isArray(source) ? [...source] : { ...source };
156
170
 
157
- Object.keys(comparison).forEach(key => {
158
- if (key in res) {
159
- if (isObject(res[key]) && isObject(comparison[key])) {
160
- res[key] = removePropsIfExisting(res[key], comparison[key]);
161
- } else if (res[key] === comparison[key]) {
162
- isArray(res) ? res.splice(key, 1) : delete res[key];
171
+ if (isArray(res)) {
172
+ for (let i = res.length - 1; i >= 0; i--) {
173
+ if (res[i] === comparison[i]) {
174
+ res.splice(i, 1);
175
+ } else if (isObject(res[i]) && isObject(comparison[i])) {
176
+ res[i] = removePropsIfExisting(res[i], comparison[i]);
163
177
  }
164
178
  }
165
- });
179
+ } else {
180
+ Object.keys(comparison).forEach(key => {
181
+ if (key in res) {
182
+ if (isObject(res[key]) && isObject(comparison[key])) {
183
+ res[key] = removePropsIfExisting(res[key], comparison[key]);
184
+ } else if (res[key] === comparison[key]) {
185
+ delete res[key];
186
+ }
187
+ }
188
+ });
189
+ }
166
190
 
167
191
  return res;
168
192
  }
@@ -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("/") : [];
@@ -8,9 +8,9 @@ const DEFAULT_PERMISSIONS = {
8
8
  delete: true
9
9
  };
10
10
 
11
- export function resolvePermissions<M extends Record<string, any>, UserType extends User>
11
+ export function resolvePermissions<M extends Record<string, any>, USER extends User>
12
12
  (collection: EntityCollection<M>,
13
- authController: AuthController<UserType>,
13
+ authController: AuthController<USER>,
14
14
  path: string,
15
15
  entity: Entity<M> | null): Permissions | undefined {
16
16
 
@@ -34,28 +34,29 @@ export function resolvePermissions<M extends Record<string, any>, UserType exten
34
34
  throw Error("New type of permission added and not mapped");
35
35
  }
36
36
 
37
- export function canEditEntity<M extends Record<string, any>, UserType extends User>
37
+ export function canEditEntity<M extends Record<string, any>, USER extends User>
38
38
  (
39
39
  collection: EntityCollection<M>,
40
- authController: AuthController<UserType>,
40
+ authController: AuthController<USER>,
41
41
  path: string,
42
42
  entity: Entity<M> | null): boolean {
43
43
  return resolvePermissions(collection, authController, path, entity)?.edit ?? DEFAULT_PERMISSIONS.edit;
44
44
  }
45
45
 
46
- export function canCreateEntity<M extends Record<string, any>, UserType extends User>
46
+ export function canCreateEntity<M extends Record<string, any>, USER extends User>
47
47
  (
48
48
  collection: EntityCollection<M>,
49
- authController: AuthController<UserType>,
49
+ authController: AuthController<USER>,
50
50
  path: string,
51
51
  entity: Entity<M> | null): boolean {
52
+ if (collection.collectionGroup) return false;
52
53
  return resolvePermissions(collection, authController, path, entity)?.create ?? DEFAULT_PERMISSIONS.create;
53
54
  }
54
55
 
55
- export function canDeleteEntity<M extends Record<string, any>, UserType extends User>
56
+ export function canDeleteEntity<M extends Record<string, any>, USER extends User>
56
57
  (
57
58
  collection: EntityCollection<M>,
58
- authController: AuthController<UserType>,
59
+ authController: AuthController<USER>,
59
60
  path: string,
60
61
  entity: Entity<M> | null): boolean {
61
62
  return resolvePermissions(collection, authController, path, entity)?.delete ?? DEFAULT_PERMISSIONS.delete;
@@ -1,7 +1,6 @@
1
1
  /**
2
2
  * Returns the plural of an English word.
3
3
  *
4
- * @export
5
4
  * @param {string} word
6
5
  * @param {number} [amount]
7
6
  * @returns {string}
@@ -92,7 +91,6 @@ export function plural(word: string, amount?: number): string {
92
91
  /**
93
92
  * Returns the singular of an English word.
94
93
  *
95
- * @export
96
94
  * @param {string} word
97
95
  * @param {number} [amount]
98
96
  * @returns {string}
@@ -1,17 +1,28 @@
1
1
  import React from "react";
2
2
 
3
- import { EntityCollection, PropertiesOrBuilders, PropertyConfig, PropertyOrBuilder, ResolvedProperty } from "../types";
3
+ import {
4
+ AuthController,
5
+ EntityCollection,
6
+ PropertiesOrBuilders,
7
+ PropertyConfig,
8
+ PropertyOrBuilder,
9
+ ResolvedProperties,
10
+ ResolvedProperty
11
+ } from "../types";
4
12
  import { isPropertyBuilder } from "./entities";
5
13
  import { resolveProperty } from "./resolutions";
6
14
  import { CircleIcon, FunctionsIcon } from "@firecms/ui";
7
15
  import { getFieldConfig } from "../core";
8
16
 
9
- export function isReferenceProperty(propertyOrBuilder: PropertyOrBuilder,
10
- fields: Record<string, PropertyConfig>) {
17
+ export function isReferenceProperty(
18
+ authController: AuthController,
19
+ propertyOrBuilder: PropertyOrBuilder,
20
+ fields: Record<string, PropertyConfig>) {
11
21
  const resolvedProperty = resolveProperty({
12
22
  propertyKey: "ignore", // TODO
13
23
  propertyOrBuilder,
14
- fields
24
+ propertyConfigs: fields,
25
+ authController
15
26
  });
16
27
  if (!resolvedProperty) return null;
17
28
  if (resolvedProperty.dataType === "reference") {
@@ -35,7 +46,7 @@ export function getIconForWidget(widget: PropertyConfig | undefined,
35
46
  }
36
47
 
37
48
  export function getIconForProperty(
38
- property: PropertyOrBuilder | ResolvedProperty,
49
+ property: PropertyOrBuilder<any> | ResolvedProperty<any>,
39
50
  size: "small" | "medium" | "large" = "small",
40
51
  fields: Record<string, PropertyConfig> = {}
41
52
  ): React.ReactNode {
@@ -63,7 +74,7 @@ export function getColorForProperty(property: PropertyOrBuilder, fields: Record<
63
74
  * @param properties
64
75
  * @param path
65
76
  */
66
- export function getPropertyInPath<M extends Record<string, any>>(properties: PropertiesOrBuilders<M>, path: string): PropertyOrBuilder<any, M> | undefined {
77
+ export function getPropertyInPath<M extends Record<string, any>>(properties: PropertiesOrBuilders<M> | ResolvedProperties, path: string): PropertyOrBuilder<any, M> | undefined {
67
78
  if (typeof properties === "object") {
68
79
  if (path in properties) {
69
80
  return properties[path];
@@ -1,21 +1,26 @@
1
- import { EntityCollection, PropertyConfig, ResolvedEntityCollection } from "../types";
1
+ import { AuthController, EntityCollection, PropertyConfig, ResolvedEntityCollection } from "../types";
2
2
  import { isReferenceProperty } from "./property_utils";
3
3
  import { isPropertyBuilder } from "./entities";
4
4
  import { getFieldConfig } from "../core";
5
5
 
6
- export function getEntityPreviewKeys(targetCollection: EntityCollection<any>,
7
- fields: Record<string, PropertyConfig>,
8
- previewProperties?: string[],
9
- limit = 3) {
6
+ export function getEntityPreviewKeys(
7
+ authController: AuthController,
8
+ targetCollection: EntityCollection<any>,
9
+ fields: Record<string, PropertyConfig>,
10
+ previewProperties?: string[],
11
+ limit = 3) {
10
12
  const allProperties = Object.keys(targetCollection.properties);
11
13
  let listProperties = previewProperties?.filter(p => allProperties.includes(p as string));
14
+ if (!listProperties && targetCollection.previewProperties) {
15
+ listProperties = targetCollection.previewProperties?.filter(p => allProperties.includes(p as string));
16
+ }
12
17
  if (listProperties && listProperties.length > 0) {
13
18
  return listProperties;
14
19
  } else {
15
20
  listProperties = allProperties;
16
21
  return listProperties.filter(key => {
17
22
  const propertyOrBuilder = targetCollection.properties[key];
18
- return propertyOrBuilder && !isPropertyBuilder(propertyOrBuilder) && !isReferenceProperty(propertyOrBuilder, fields);
23
+ return propertyOrBuilder && !isPropertyBuilder(propertyOrBuilder) && !isReferenceProperty(authController, propertyOrBuilder, fields);
19
24
  }).slice(0, limit);
20
25
  }
21
26
  }
@@ -39,13 +44,19 @@ export function getEntityTitlePropertyKey<M extends Record<string, any>>(collect
39
44
 
40
45
  export function getEntityImagePreviewPropertyKey<M extends object>(collection: ResolvedEntityCollection<M>): string | undefined {
41
46
 
42
- // find first text field property
47
+ // find first storage property of type image
43
48
  for (const key in collection.properties) {
44
49
  const property = collection.properties[key];
45
50
  if (property.dataType === "string" && property.storage?.acceptedFiles?.includes("image/*")) {
46
51
  return key;
47
52
  }
48
-
53
+ }
54
+ // alternatively, look for the first array of images
55
+ for (const key in collection.properties) {
56
+ const property = collection.properties[key];
57
+ if (property.dataType === "array" && property.of?.dataType === "string" && property.of.storage?.acceptedFiles?.includes("image/*")) {
58
+ return key;
59
+ }
49
60
  }
50
61
  return undefined;
51
62
  }